Корутине су засноване на концепту генератора где функција може дати вредности и касније бити настављена да би наставила са извршавањем. Корутине пружају моћан алат за управљање асинхроним операцијама и могу значајно побољшати укупан квалитет вашег кода.
Употреба корутина
Корутине су потребне из неколико разлога у савременом програмирању, посебно у језицима као што је Ц++. Ево неколико кључних разлога зашто су корутине корисне:
Корутине пружају елегантно решење за асинхроно програмирање. Они омогућавају креирање кода који изгледа секвенцијално и блокирајуће, о чему је лакше размишљати и разумети. Корутине могу да обуставе своје извршавање у одређеним тачкама без блокирања нити, омогућавајући паралелни рад других задатака. Због тога се системски ресурси могу ефикасније користити, а одзив је повећан у апликацијама које укључују И/О операције или чекање на екстерне догађаје.
Они могу учинити код лакшим за разумевање и одржавање. Елиминишући сложене ланце повратног позива или државне машине, корутине омогућавају да се код пише у линеарнијем и секвенцијалном стилу. Ово побољшава организацију кода, смањује угнежђење и чини логику лако разумљивом.
Корутине пружају структуиран начин за руковање конкурентношћу и паралелизмом. Они вам омогућавају да изразите сложене обрасце координације и асинхроне токове рада користећи интуитивнију синтаксу. За разлику од традиционалних модела нити у којима се нити могу блокирати, корутине могу ослободити системске ресурсе и омогућити ефикасан мултитаскинг.
Хајде да направимо неколико примера да демонстрирамо имплементацију корутина у Ц++.
Пример 1: Основне корутине
Основни пример корутина је дат у следећем:
#инцлуде <иостреам>
#инцлуде <корутина>
струцт ТхисЦороут {
струцт обећање_тип {
ТхисЦороут гет_ретурн_објецт ( ) { повратак { } ; }
стд :: суспенд_невер инитиал_суспенд ( ) { повратак { } ; }
стд :: суспенд_невер финал_суспенд ( ) ноекцепт { повратак { } ; }
празнина унхандлед_екцептион ( ) { }
празнина ретурн_воид ( ) { }
} ;
боол аваит_реади ( ) { повратак лажно ; }
празнина аваит_суспенд ( стд :: цороутине_хандле <> х ) { }
празнина аваит_ресуме ( ) { стд :: цоут << „Корутина је настављена.“ << стд :: ендл ; }
} ;
ТхисЦороут фоо ( ) {
стд :: цоут << „Корутина је почела.“ << стд :: ендл ;
цо_аваит стд :: суспенд_алваис { } ;
цо_ретурн ;
}
инт главни ( ) {
ауто кр = фоо ( ) ;
стд :: цоут << „Корутина је створена.“ << стд :: ендл ;
кр. аваит_ресуме ( ) ;
стд :: цоут << „Корутина је завршена.“ << стд :: ендл ;
повратак 0 ;
}
Хајде да прођемо кроз претходно наведени код и детаљно га објаснимо:
Након укључивања потребних датотека заглавља, дефинишемо структуру „ТхисЦороут“ која представља корутину. Унутар „ТхисЦороут“ дефинисана је друга структура која је „промисе_типе“ која рукује обећањем корутине. Ова структура обезбеђује различите функције које су потребне машини корутине.
Унутар заграда користимо функцију гет_ретурн_објецт(). Враћа сам објекат корутине. У овом случају, враћа празан објекат „ТхисЦороут“. Затим се позива функција инитиал_суспенд() која одређује понашање када се корутина први пут покрене. стд::суспенд_невер значи да корутина не би требало да буде суспендована у почетку.
Након тога, имамо функцију финал_суспенд() која одређује понашање када се корутина ускоро завршава. стд::суспенд_невер значи да корутину не треба суспендовати пре њеног финализације.
Ако корутина избаци изузетак, позива се метод унхандлед_екцептион(). У овом примеру, то је празна функција, али можете да обрађујете изузетке по потреби. Када се корутина заврши без давања вредности, позива се метода ретурн_воид(). У овом случају, то је такође празна функција.
Такође дефинишемо три функције члана у оквиру „ТхисЦороут“. Функција аваит_реади() се позива да провери да ли је корутина спремна да настави са извршавањем. У овом примеру увек враћа нетачно што указује да корутина није спремна да се одмах настави. Када ће корутина бити суспендована, позива се метод аваит_суспенд(). Овде је то празна функција што значи да суспензија није потребна. Програм позива аваит_ресуме() када се корутина настави након суспензије. Само шаље поруку која каже да је корутина настављена.
Следећи редови кода дефинишу функцију корутине фоо(). Унутар фоо(), почињемо штампањем поруке у којој се наводи да је корутина почела. Затим се цо_аваит стд::суспенд_алваис{} користи за суспендовање корутине и указује да се може наставити касније. Наредба цо_ретурн се користи за завршетак корутине без враћања било какве вредности.
У функцији маин() конструишемо објекат „цр“ типа „ТхисЦороут“ позивањем фоо(). Ово креира и покреће корутину. Затим се штампа порука која каже да је корутина креирана. Затим позивамо аваит_ресуме() на објекту корутине „цр“ да бисмо наставили његово извршавање. Унутар аваит_ресуме(), штампа се порука „Корутина је настављена“. На крају, приказујемо поруку која каже да је корутина завршена пре него што се програм заврши.
Када покренете овај програм, излаз је следећи:
Пример 2: Корутина са параметрима и приносом
Сада, за ову илустрацију, пружамо код који демонстрира употребу корутина са параметрима и попуштање у Ц++ за креирање понашања сличног генератору за производњу низа бројева.
#инцлуде <иостреам>#инцлуде <корутина>
#инцлуде <вектор>
струцт НЕВЦороутине {
струцт п_типе {
стд :: вектор < инт > вредности ;
НОВАКорутина гет_ретурн_објецт ( ) { повратак { } ; }
стд :: суспенд_алваис инитиал_суспенд ( ) { повратак { } ; }
стд :: суспенд_алваис финал_суспенд ( ) ноекцепт { повратак { } ; }
празнина унхандлед_екцептион ( ) { }
празнина ретурн_воид ( ) { }
стд :: суспенд_алваис вредност_приноса ( инт вредност ) {
вредности. потисне ( вредност ) ;
повратак { } ;
}
} ;
стд :: вектор < инт > вредности ;
струцт итератор {
стд :: цороутине_хандле <> цхорус_хандле ;
боол оператор != ( конст итератор & друго ) конст { повратак цхорус_хандле != друго. цхорус_хандле ; }
итератор & оператер ++ ( ) { цхорус_хандле. Резиме ( ) ; повратак * ово ; }
инт оператер * ( ) конст { повратак цхорус_хандле. обећање ( ) . вредности [ 0 ] ; }
} ;
итератор почиње ( ) { повратак итератор { стд :: цороутине_хандле < п_типе >:: фром_промисе ( обећање ( ) ) } ; }
крај итератора ( ) { повратак итератор { нуллптр } ; }
стд :: цороутине_хандле < п_типе > обећање ( ) { повратак
стд :: цороутине_хандле < п_типе >:: фром_промисе ( * ово ) ; }
} ;
НЕВЦорутине генератеНумберс ( ) {
цо_ииелд 5 ;
цо_ииелд 6 ;
цо_ииелд 7 ;
}
инт главни ( ) {
НОВОЦороутине нц = генератеНумберс ( ) ;
за ( инт вредност : нц ) {
стд :: цоут << вредност << ' ' ;
}
стд :: цоут << стд :: ендл ;
повратак 0 ;
}
У претходном коду, структура НЕВЦороутине представља генератор заснован на корутини. Садржи угнежђену структуру „п_типе“ која служи као тип обећања за корутину. Структура п_типе дефинише функције које су потребне машини корутине као што су гет_ретурн_објецт(), инитиал_суспенд(), финал_суспенд(), унхандлед_екцептион() и ретурн_воид(). Структура п_типе такође укључује функцију ииелд_валуе(инт валуе) која се користи за добијање вредности из корутине. Он додаје дату вредност вектору вредности.
Структура НЕВЦороутине укључује променљиву члана стд::вецтор<инт> под називом „вредности“ која представља генерисане вредности. Унутар НЕВЦороутине, постоји угнежђени итератор структуре који омогућава итерацију преко генерисаних вредности. Садржи цоро_хандле који је ручица корутине и дефинише операторе као што су !=, ++ и * за итерацију.
Користимо функцију бегин() да креирамо итератор на почетку корутине тако што ћемо добити цоро_хандле из обећања п_типе. Док функција енд() креира итератор који представља крај корутине и конструисан је са нуллптр цоро_хандле-ом. Након тога, функција обећања() се користи за враћање типа обећања креирањем цороутине_хандле из обећања п_типе. ГенерирајНумберс() функција је корутина која даје три вредности – 5, 6 и 7 – користећи кључну реч цо_ииелд.
У функцији маин(), инстанца НЕВЦороутине под називом „нц“ се креира позивањем генериснумберс() корутине. Ово иницијализује корутину и бележи њено стање. Петља „фор“ заснована на опсегу користи се за понављање вредности „нц“, а свака вредност се штампа која је одвојена размаком помоћу стд::цоут.
Генерисани излаз је следећи:
Закључак
Овај чланак показује коришћење корутина у Ц++. Разговарали смо о два примера. За прву илустрацију, основна корутина је креирана у Ц++ програму користећи функције корутине. Док је друга демонстрација изведена коришћењем корутина са параметрима и генерисањем понашања сличног генератору за креирање низа бројева.