C++ Coroutines Примери

C Coroutines Primeri



Съпрограмите предоставят езикова функция, която ви позволява да пишете асинхронния код по по-организиран и линеен начин, насърчавайки структуриран и последователен подход. Те дават механизъм за поставяне на пауза и рестартиране на изпълнението на функция в конкретни моменти, без да се спира цялата нишка. Съпрограмите са полезни при работа със задачи, които изискват изчакване на I/O операции като четене от файл или изпращане на мрежово повикване.

Съпрограмите се основават на концепцията за генератори, където дадена функция може да даде стойности и по-късно да бъде възобновена, за да продължи изпълнението. Coroutines осигуряват мощен инструмент за управление на асинхронните операции и могат значително да подобрят цялостното качество на вашия код.

Използване на Coroutines

Корутините са необходими по няколко причини в съвременното програмиране, особено в езици като C++. Ето някои ключови причини, поради които корутините са полезни:







Coroutines осигуряват елегантно решение за асинхронно програмиране. Те правят възможно създаването на код, който изглежда последователен и блокиращ, което е по-лесно за разсъждение и разбиране. Съпрограмите могат да спрат изпълнението си в определени точки, без да блокират нишките, позволявайки паралелна работа на други задачи. Поради това системните ресурси могат да се използват по-ефективно и отзивчивостта се увеличава в приложения, които включват I/O операции или чакат външни събития.



Те могат да направят кода по-лесен за разбиране и поддръжка. Чрез елиминиране на сложните вериги за обратно извикване или държавни машини, съпрограммите позволяват кодът да бъде написан в по-линеен и последователен стил. Това подобрява организацията на кода, намалява влагането и прави логиката лесна за разбиране.



Корутините предоставят структуриран начин за справяне с едновременността и паралелизма. Те ви позволяват да изразите сложните координационни модели и асинхронните работни потоци, като използвате по-интуитивен синтаксис. За разлика от традиционните модели на нишки, при които нишките могат да бъдат блокирани, съпрограммите могат да освободят системните ресурси и да позволят ефективна многозадачност.





Нека създадем няколко примера, за да демонстрираме внедряването на съпрограмми в C++.

Пример 1: Основни корутини

Примерът за основни съпрограмми е даден по-долу:



#include

#include

структура ThisCorout {

структура тип_обещание {

ThisCorout get_return_object ( ) { връщане { } ; }

std :: suspend_never първоначално_спиране ( ) { връщане { } ; }

std :: suspend_never окончателно_спиране ( ) noexcept { връщане { } ; }

невалиден необработено_изключение ( ) { }

невалиден return_void ( ) { }

} ;

bool await_ready ( ) { връщане невярно ; }

невалиден await_suspend ( std :: манипулатор на съпрограма <> ч ) { }

невалиден await_resume ( ) { std :: cout << „Корутината е възобновена.“ << std :: endl ; }

} ;

Това е Corout foo ( ) {

std :: cout << „Корутината започна.“ << std :: endl ;

co_await std :: suspend_always { } ;

съвместно_връщане ;

}

вътр основен ( ) {

Автоматичен кр = Фу ( ) ;

std :: cout << „Корутината е създадена.“ << std :: endl ;

кр. await_resume ( ) ;

std :: cout << „Корутината приключи.“ << std :: endl ;

връщане 0 ;

}

Нека да преминем през предоставения по-рано код и да го обясним подробно:

След като включим необходимите заглавни файлове, ние дефинираме структурата „ThisCorout“, която представлява съпрограма. Вътре в „ThisCorout“ е дефинирана друга структура, която е „promise_type“, която обработва обещанието на съпрограмата. Тази структура предоставя различни функции, които се изискват от сърутинната машина.

Вътре в скобите използваме функцията get_return_object(). Той връща самия обект на съпрограма. В този случай той връща празен обект „ThisCorout“. След това се извиква функцията initial_suspend(), която определя поведението при първото стартиране на съпрограмата. std::suspend_never означава, че съпрограмата не трябва да бъде спряна първоначално.

След това имаме функцията final_suspend(), която определя поведението, когато съпрограмата е на път да приключи. std::suspend_never означава, че съпрограмата не трябва да бъде суспендирана преди нейното финализиране.

Ако съпрограма хвърли изключение, се извиква методът unhandled_exception(). В този пример това е празна функция, но можете да обработвате изключенията според нуждите. Когато съпрограмата приключи, без да даде стойност, се извиква методът return_void(). В този случай това също е празна функция.

Ние също така дефинираме три членски функции в „ThisCorout“. Функцията await_ready() се извиква, за да провери дали съпрограмата е готова да поднови изпълнението. В този пример той винаги връща false, което показва, че съпрограмата не е готова за незабавно възобновяване. Когато съпрограмата ще бъде спряна, се извиква методът await_suspend(). Тук това е празна функция, което означава, че не е необходимо спиране. Програмата извиква await_resume(), когато съпрограмата се възобнови след спиране. Той просто извежда съобщение, което гласи, че съпрограмата е възобновена.

Следващите редове от кода дефинират съпрограмата foo(). Вътре във foo() започваме с отпечатване на съобщение, което гласи, че съпрограмата е стартирана. След това co_await std::suspend_always{} се използва за спиране на съпрограмата и показва, че тя може да бъде възобновена на по-късен етап. Операторът co_return се използва за завършване на съпрограмата без връщане на стойност.

Във функцията main() конструираме обект „cr“ от тип „ThisCorout“ чрез извикване на foo(). Това създава и стартира сърутината. След това се отпечатва съобщение, което гласи, че съпрограмата е създадена. След това извикваме await_resume() на обекта на съпрограмата „cr“, за да възобновим изпълнението му. Вътре в await_resume() се отпечатва съобщението „Съпрограмата е възобновена“. Накрая показваме съобщение, което гласи, че съпрограмата е завършена, преди програмата да приключи.

Когато стартирате тази програма, изходът е както следва:

Пример 2: Съпрограма с параметри и добив

Сега, за тази илюстрация, предоставяме код, който демонстрира използването на съпрограми с параметри и yielding в C++ за създаване на подобно на генератор поведение за създаване на поредица от числа.

#include

#include

#include <вектор>

структура НОВА рутина {

структура p_type {

std :: вектор < вътр > стойности ;

НОВАКорутина get_return_object ( ) { връщане { } ; }

std :: suspend_always първоначално_спиране ( ) { връщане { } ; }

std :: suspend_always окончателно_спиране ( ) noexcept { връщане { } ; }

невалиден необработено_изключение ( ) { }

невалиден return_void ( ) { }

std :: suspend_always yield_value ( вътр стойност ) {

стойности. избутвам ( стойност ) ;

връщане { } ;

}

} ;

std :: вектор < вътр > стойности ;

структура итератор {

std :: манипулатор на съпрограма <> chorus_handle ;

bool оператор != ( конст итератор и друго ) конст { връщане chorus_handle != друго. chorus_handle ; }

итератор и оператор ++ ( ) { chorus_handle. продължи ( ) ; връщане * това ; }

вътр оператор * ( ) конст { връщане chorus_handle. обещание ( ) . стойности [ 0 ] ; }

} ;

начало на итератора ( ) { връщане итератор { std :: манипулатор на съпрограма < p_type >:: от_обещание ( обещание ( ) ) } ; }

край на итератора ( ) { връщане итератор { nullptr } ; }

std :: манипулатор на съпрограма < p_type > обещание ( ) { връщане
std :: манипулатор на съпрограма < p_type >:: от_обещание ( * това ) ; }

} ;

NEWCoroutine generateNumbers ( ) {

co_yield 5 ;

co_yield 6 ;

co_yield 7 ;

}

вътр основен ( ) {

НОВОCoroutine nc = генериране на числа ( ) ;

за ( вътр стойност : nc ) {

std :: cout << стойност << ' ' ;

}

std :: cout << std :: endl ;

връщане 0 ;

}

В предишния код структурата NEWCoroutine представлява базиран на съпрограма генератор. Той съдържа вложена структура „p_type“, която служи като обещаващ тип за съпрограмата. Структурата p_type дефинира функциите, които се изискват от сърутинната машина, като get_return_object(), initial_suspend(), final_suspend(), unhandled_exception() и return_void(). Структурата p_type също включва функцията yield_value(int value), която се използва за получаване на стойностите от съпрограмата. Той добавя предоставената стойност към вектора на стойностите.

Структурата NEWCoroutine включва членската променлива std::vector , наречена „стойности“, която представлява генерираните стойности. Вътре в NEWCoroutine има вложен итератор на структура, който позволява итериране на генерираните стойности. Той съдържа coro_handle, който е манипулатор на съпрограмата и дефинира операторите като !=, ++ и * за итерация.

Използваме функцията begin(), за да създадем итератор в началото на съпрограмата, като получим coro_handle от обещанието p_type. Докато функцията end() създава итератор, който представлява края на съпрограмата и е конструиран с nullptr coro_handle. След това функцията promise() се използва за връщане на типа обещание чрез създаване на coroutine_handle от обещанието p_type. Функцията generateNumbers() е съпрограма, която дава три стойности – 5, 6 и 7 – с помощта на ключовата дума co_yield.

Във функцията main() се създава екземпляр на NEWCoroutine с име „nc“ чрез извикване на съпрограмата generateNumbers(). Това инициализира съпрограмата и улавя нейното състояние. Използва се цикъл „for“, базиран на диапазон, за итериране на стойностите на „nc“ и всяка стойност се отпечатва, които са разделени с интервал, използвайки std::cout.

Генерираният изход е както следва:

Заключение

Тази статия демонстрира използването на съпрограмми в C++. Обсъдихме два примера. За първата илюстрация основната съпрограма е създадена в C++ програма с помощта на функциите на съпрограмата. Докато втората демонстрация беше извършена чрез използване на съпрограми с параметри и отдаване за генериране на подобно на генератор поведение за създаване на поредица от числа.