A korutinok a generátorok koncepcióján alapulnak, ahol a függvény értékeket adhat, és később folytathatja a végrehajtást. A korutinok hatékony eszközt biztosítanak az aszinkron műveletek kezeléséhez, és nagymértékben javíthatják a kód általános minőségét.
A korutinok felhasználása
A korutinokra több okból is szükség van a modern programozásban, különösen az olyan nyelvekben, mint a C++. Íme néhány fő ok, amiért a korutin hasznos:
A korutinok elegáns megoldást nyújtanak az aszinkron programozáshoz. Lehetővé teszik egy olyan kód létrehozását, amely szekvenciálisnak tűnik, és blokkolja, amelyet egyszerűbb megfontolni és megérteni. A korutinok bizonyos pontokon felfüggeszthetik végrehajtásukat a szálak blokkolása nélkül, lehetővé téve más feladatok párhuzamos működését. Emiatt a rendszer erőforrásai hatékonyabban használhatók fel, és az I/O műveleteket magába foglaló vagy külső eseményekre váró alkalmazásokban megnő a válaszkészség.
Ezek megkönnyíthetik a kód megértését és karbantartását. Az összetett visszahívási láncok vagy állapotgépek kiiktatásával a korutinok lehetővé teszik a kód lineárisabb és szekvenciálisabb stílusban történő megírását. Ez javítja a kódszervezést, csökkenti a beágyazást, és könnyen érthetővé teszi a logikát.
A korutinok strukturált módot biztosítanak az egyidejűség és a párhuzamosság kezelésére. Lehetővé teszik az összetett koordinációs minták és aszinkron munkafolyamatok kifejezését egy intuitívabb szintaxis használatával. A hagyományos szálfűzési modellekkel ellentétben, ahol a szálak blokkolva lehetnek, a korutinok felszabadíthatják a rendszer erőforrásait, és hatékony többfeladatos munkavégzést tesznek lehetővé.
Hozzunk létre néhány példát a korutinok megvalósításának bemutatására C++ nyelven.
1. példa: Alapvető korutinok
Az alapvető korutin példája az alábbiakban található:
#include
#include
struct ThisCorout {
struct ígéret_típus {
ThisCorout get_return_object ( ) { Visszatérés { } ; }
std :: felfüggeszt_soha kezdeti_felfüggesztés ( ) { Visszatérés { } ; }
std :: felfüggeszt_soha final_suspend ( ) nem, kivéve { Visszatérés { } ; }
üres nem kezelt kivétel ( ) { }
üres return_void ( ) { }
} ;
bool await_ready ( ) { Visszatérés hamis ; }
üres await_suspend ( std :: coroutine_handle <> h ) { }
üres await_resume ( ) { std :: cout << – A Coroutine folytatódik. << std :: endl ; }
} ;
ThisCorout foo ( ) {
std :: cout << – Elkezdődött a korutin. << std :: endl ;
co_await std :: felfüggeszt_mindig { } ;
co_return ;
}
int fő- ( ) {
auto cr = foo ( ) ;
std :: cout << 'A korutína létrejött.' << std :: endl ;
cr. await_resume ( ) ;
std :: cout << – A korutin véget ért. << std :: endl ;
Visszatérés 0 ;
}
Nézzük át a korábban megadott kódot, és magyarázzuk el részletesen:
A szükséges fejlécfájlok megadása után meghatározzuk a „ThisCorout” struktúrát, amely egy korutint képvisel. A „ThisCorout”-on belül egy másik „promise_type” struktúra van definiálva, amely kezeli a korutin ígéretét. Ez a struktúra különféle funkciókat biztosít, amelyekre a korutin gépezetnek szüksége van.
A zárójelben a get_return_object() függvényt használjuk. Magát a korutin objektumot adja vissza. Ebben az esetben egy üres „ThisCorout” objektumot ad vissza. Ezután a kezdeti_suspend() függvény meghívásra kerül, amely meghatározza a korutint első indításakor bekövetkező viselkedést. Az std::suspend_never azt jelenti, hogy a korutint nem szabad kezdetben felfüggeszteni.
Ezt követően van a final_suspend() függvény, amely meghatározza a viselkedést, amikor a korutin hamarosan befejeződik. Az std::suspend_never azt jelenti, hogy a korutint nem szabad felfüggeszteni a véglegesítése előtt.
Ha egy korutin kivételt dob, akkor az unhandled_exception() metódus kerül meghívásra. Ebben a példában ez egy üres függvény, de szükség szerint kezelheti a kivételeket. Amikor a korutin érték megadása nélkül fejeződik be, a return_void() metódus meghívásra kerül. Ebben az esetben ez is egy üres függvény.
Három tagfüggvényt is meghatározunk a „ThisCorout”-on belül. Az await_ready() függvény meghívása annak ellenőrzésére, hogy a korutin készen áll-e a végrehajtás folytatására. Ebben a példában mindig false értéket ad vissza, ami azt jelzi, hogy a korutin nem áll készen az azonnali folytatásra. Amikor a korutint felfüggesztik, az await_suspend() metódus kerül meghívásra. Itt ez egy üres funkció, ami azt jelenti, hogy nincs szükség felfüggesztésre. A program meghívja az await_resume() függvényt, amikor a korutint a felfüggesztés után folytatják. Csak egy üzenetet ad ki, amely kijelenti, hogy a korutin újraindult.
A kód következő sorai a foo() corutine függvényt határozzák meg. A foo()-ban először egy üzenetet nyomtatunk, amely kijelenti, hogy a korutin elindult. Ezután a co_await std::suspend_always{} a korutint felfüggesztésére használja, és jelzi, hogy egy későbbi időpontban újraindítható. A co_return utasítás a korutint érték visszaadása nélkül fejezi be.
A main() függvényben egy „ThisCorout” típusú „cr” objektumot készítünk a foo() meghívásával. Ez létrehozza és elindítja a korutint. Ezután egy üzenetet nyomtat, amely jelzi, hogy a korutint létrehozták. Ezután meghívjuk az await_resume()-t a „cr” korutine objektumon a végrehajtás folytatásához. Az await_resume()-ban megjelenik a „A korutin folytatása” üzenet. Végül megjelenítünk egy üzenetet, amely kijelenti, hogy a korutint a program leállása előtt befejeződött.
A program futtatásakor a kimenet a következő:
2. példa: Korutin paraméterekkel és hozamgal
Most, ehhez az illusztrációhoz adunk egy kódot, amely bemutatja a paraméterekkel rendelkező korutinok használatát C++-ban, hogy generátorszerű viselkedést hozzon létre számsorozat létrehozásához.
#include#include
#include
struct ÚJKorutin {
struct p_type {
std :: vektor < int > értékeket ;
NEWCoroutine get_return_object ( ) { Visszatérés { } ; }
std :: felfüggeszt_mindig kezdeti_felfüggesztés ( ) { Visszatérés { } ; }
std :: felfüggeszt_mindig final_suspend ( ) nem, kivéve { Visszatérés { } ; }
üres nem kezelt kivétel ( ) { }
üres return_void ( ) { }
std :: felfüggeszt_mindig hozam_érték ( int érték ) {
értékeket. visszavet ( érték ) ;
Visszatérés { } ;
}
} ;
std :: vektor < int > értékeket ;
struct iterátor {
std :: coroutine_handle <> chorus_handle ;
bool operátor != ( const iterátor & Egyéb ) const { Visszatérés chorus_handle != Egyéb. chorus_handle ; }
iterátor & operátor ++ ( ) { chorus_handle. önéletrajz ( ) ; Visszatérés * ez ; }
int operátor * ( ) const { Visszatérés chorus_handle. ígéret ( ) . értékeket [ 0 ] ; }
} ;
az iterátor elindul ( ) { Visszatérés iterátor { std :: coroutine_handle < p_type >:: from_promise ( ígéret ( ) ) } ; }
iterátor vége ( ) { Visszatérés iterátor { nullptr } ; }
std :: coroutine_handle < p_type > ígéret ( ) { Visszatérés
std :: coroutine_handle < p_type >:: from_promise ( * ez ) ; }
} ;
NEWCoroutine generálNumbers ( ) {
co_yield 5 ;
co_yield 6 ;
co_yield 7 ;
}
int fő- ( ) {
NEWCoroutine nc = generNumbers ( ) ;
számára ( int érték : nc ) {
std :: cout << érték << ' ' ;
}
std :: cout << std :: endl ;
Visszatérés 0 ;
}
Az előző kódban a NEWCoroutine struktúra korutin alapú generátort jelent. Tartalmaz egy beágyazott „p_type” struktúrát, amely ígérettípusként szolgál a korutin számára. A p_type struktúra határozza meg azokat a függvényeket, amelyekre a korutin gépezetnek szüksége van, mint például a get_return_object(), a kezdeti_suspend(), a final_suspend(), az unhandled_exception() és a return_void(). A p_type struktúra tartalmazza a result_value(int value) függvényt is, amely a korutinból származó értékek előállítására szolgál. A megadott értéket hozzáadja az értékvektorhoz.
A NEWCoroutine struktúra tartalmazza az std::vector
A begin() függvényt használjuk egy iterátor létrehozására a korutín elején úgy, hogy megkapjuk a coro_handle paramétert a p_type ígéretből. Míg az end() függvény egy iterátort hoz létre, amely a korutin végét reprezentálja, és nullptr coro_handle-lel van felépítve. Ezt követően az ígéret() függvényt használjuk az ígéret típusának visszaadására úgy, hogy létrehozunk egy coroutine_handle-t a p_type ígéretből. A generateNumbers() függvény egy korutin, amely a co_yield kulcsszó használatával három értéket ad – 5, 6 és 7.
A main() függvényben a NEWCoroutine „nc” nevű példánya jön létre a generateNumbers() korutin meghívásával. Ez inicializálja a korutint és rögzíti az állapotát. Egy tartomány alapú 'for' ciklust használnak az 'nc' értékei áttételére, és minden egyes érték kinyomtatásra kerül, amelyeket szóközzel választanak el az std::cout használatával.
A generált kimenet a következő:
Következtetés
Ez a cikk a korutinok használatát mutatja be C++ nyelven. Két példát tárgyaltunk. Az első szemléltetésre az alap korutint egy C++ programban hozzuk létre a korutin függvények segítségével. Míg a második demonstrációt a korutinok paraméterekkel való felhasználásával végeztük, és engedve generátorszerű viselkedést generáltunk egy számsorozat létrehozásához.