Příklady C++ Coroutines

Priklady C Coroutines



Coroutines poskytují jazykovou funkci, která vám umožňuje psát asynchronní kód organizovanějším a lineárnějším způsobem a podporuje strukturovaný a sekvenční přístup. Poskytují mechanismus pro pozastavení a opětovné spuštění funkce v konkrétních instancích, aniž by se zastavilo celé vlákno. Korutiny jsou užitečné při zpracování úloh, které vyžadují čekání na I/O operace, jako je čtení ze souboru nebo odesílání síťového volání.

Korutiny jsou založeny na konceptu generátorů, kde funkce může poskytovat hodnoty a později být obnovena, aby pokračovala v provádění. Coroutines poskytují výkonný nástroj pro správu asynchronních operací a mohou výrazně zlepšit celkovou kvalitu vašeho kódu.

Použití korutínů

Korutiny jsou v moderním programování potřeba z několika důvodů, zejména v jazycích jako C++. Zde je několik klíčových důvodů, proč jsou koroutiny prospěšné:







Korutiny poskytují elegantní řešení asynchronního programování. Umožňují vytvořit kód, který se jeví jako sekvenční a blokující, což je jednodušší na uvažování a pochopení. Korutiny mohou pozastavit své provádění v určitých bodech bez blokování vláken, což umožňuje paralelní provoz jiných úloh. Díky tomu mohou být systémové prostředky využívány efektivněji a u aplikací, které zahrnují I/O operace nebo čekání na externí události, je zvýšená odezva.



Mohou usnadnit pochopení a údržbu kódu. Odstraněním složitých řetězců zpětných volání nebo stavových automatů umožňují korutiny psát kód lineárnějším a sekvenčním stylem. To zlepšuje organizaci kódu, snižuje vnořování a usnadňuje pochopení logiky.



Korutiny poskytují strukturovaný způsob, jak zvládnout souběžnost a paralelismus. Umožňují vám vyjádřit složité koordinační vzorce a asynchronní pracovní postupy pomocí intuitivnější syntaxe. Na rozdíl od tradičních modelů vláken, kde mohou být vlákna blokována, mohou korutiny uvolnit systémové prostředky a umožnit efektivní multitasking.





Vytvořme několik příkladů, které demonstrují implementaci korutin v C++.

Příklad 1: Základní korutiny

Základní příklad korutin je uveden v následujícím textu:



#include

#include

strukturovat Tento Corout {

strukturovat typ_příslibu {

ThisCorout get_return_object ( ) { vrátit se { } ; }

std :: pozastavit_nikdy initial_suspend ( ) { vrátit se { } ; }

std :: pozastavit_nikdy final_suspend ( ) no kromě { vrátit se { } ; }

prázdnota neošetřená_výjimka ( ) { }

prázdnota return_void ( ) { }

} ;

bool wait_ready ( ) { vrátit se Nepravdivé ; }

prázdnota čekat_pozastavit ( std :: coroutine_handle <> h ) { }

prázdnota wait_resume ( ) { std :: cout << 'Coroutine je obnoven.' << std :: endl ; }

} ;

ThisCorout foo ( ) {

std :: cout << 'Coroutine začala.' << std :: endl ;

co_await std :: suspend_always { } ;

co_return ;

}

int hlavní ( ) {

auto kr = foo ( ) ;

std :: cout << 'Coroutine je vytvořen.' << std :: endl ;

kr. wait_resume ( ) ;

std :: cout << 'Coroutine skončil.' << std :: endl ;

vrátit se 0 ;

}

Pojďme si projít dříve poskytnutý kód a podrobně ho vysvětlit:

Po zahrnutí požadovaných hlavičkových souborů definujeme strukturu „ThisCorout“, která představuje korutinu. Uvnitř „ThisCorout“ je definována další struktura, která je „promise_type“, která zpracovává příslib koroutiny. Tato struktura poskytuje různé funkce, které vyžaduje koroutinový aparát.

V závorkách používáme funkci get_return_object(). Vrací samotný objekt coroutine. V tomto případě vrátí prázdný objekt „ThisCorout“. Poté je vyvolána funkce initial_suspend(), která určuje chování při prvním spuštění korutiny. std::suspend_never znamená, že koroutina by neměla být zpočátku pozastavena.

Poté máme funkci final_suspend(), která určuje chování, když se koroutina blíží ke konci. std::suspend_never znamená, že koroutina by neměla být pozastavena před jejím dokončením.

Pokud coroutine vyvolá výjimku, vyvolá se metoda unhandled_exception() . V tomto příkladu je to prázdná funkce, ale můžete podle potřeby zpracovat výjimky. Když se rutina ukončí bez získání hodnoty, je vyvolána metoda return_void(). V tomto případě je to také prázdná funkce.

V rámci „ThisCorout“ také definujeme tři členské funkce. Funkce wait_ready() je volána, aby zkontrolovala, zda je koroutina připravena pokračovat v provádění. V tomto příkladu vždy vrátí hodnotu false, což znamená, že koroutina není připravena okamžitě pokračovat. Když má být koroutina pozastavena, zavolá se metoda wait_suspend(). Zde je to prázdná funkce, což znamená, že není nutné žádné pozastavení. Program volá wait_resume(), když je koroutina obnovena po pozastavení. Vypíše pouze zprávu, která říká, že korutina byla obnovena.

Další řádky kódu definují funkci foo() coroutine. Uvnitř foo() začneme vytištěním zprávy, která říká, že koroutina začala. Poté se co_await std::suspend_always{} použije k pozastavení korutiny a indikuje, že v ní lze pokračovat později. Příkaz co_return se používá k dokončení coroutine bez vracení jakékoli hodnoty.

Ve funkci main() zkonstruujeme objekt „cr“ typu „ThisCorout“ voláním foo(). Tím se vytvoří a spustí koroutin. Poté se vytiskne zpráva, že koroutina byla vytvořena. Dále zavoláme wait_resume() na objektu coroutine „cr“, abychom obnovili jeho provádění. Uvnitř wait_resume() se vytiskne zpráva „The Coroutine is continueed“. Nakonec zobrazíme zprávu, která oznamuje, že koroutina je dokončena před ukončením programu.

Když spustíte tento program, výstup je následující:

Příklad 2: Korutina s parametry a výtěžností

Nyní pro tuto ilustraci poskytujeme kód, který demonstruje použití korutin s parametry a výnosem v C++ k vytvoření chování podobného generátoru pro vytvoření posloupnosti čísel.

#include

#include

#include

strukturovat NEWCorutina {

strukturovat p_type {

std :: vektor < int > hodnoty ;

NEWCoroutine get_return_object ( ) { vrátit se { } ; }

std :: suspend_always initial_suspend ( ) { vrátit se { } ; }

std :: suspend_always final_suspend ( ) no kromě { vrátit se { } ; }

prázdnota neošetřená_výjimka ( ) { }

prázdnota return_void ( ) { }

std :: suspend_always výnos_hodnota ( int hodnota ) {

hodnoty. zatlačit zpátky ( hodnota ) ;

vrátit se { } ;

}

} ;

std :: vektor < int > hodnoty ;

strukturovat iterátor {

std :: coroutine_handle <> chorus_handle ;

boolův operátor != ( konst iterátor & jiný ) konst { vrátit se chorus_handle != jiný. chorus_handle ; }

iterátor & operátor ++ ( ) { chorus_handle. životopis ( ) ; vrátit se * tento ; }

int operátor * ( ) konst { vrátit se chorus_handle. slib ( ) . hodnoty [ 0 ] ; }

} ;

iterátor začíná ( ) { vrátit se iterátor { std :: coroutine_handle < p_type >:: od_slibu ( slib ( ) ) } ; }

konec iterátoru ( ) { vrátit se iterátor { nullptr } ; }

std :: coroutine_handle < p_type > slib ( ) { vrátit se
std :: coroutine_handle < p_type >:: od_slibu ( * tento ) ; }

} ;

NEWCorutina generovatNumbers ( ) {

ko_výnos 5 ;

ko_výnos 6 ;

ko_výnos 7 ;

}

int hlavní ( ) {

NEWCoroutine nc = generovatNumbers ( ) ;

pro ( int hodnota : nc ) {

std :: cout << hodnota << '' ;

}

std :: cout << std :: endl ;

vrátit se 0 ;

}

V předchozím kódu představuje struktura NEWCoroutine generátor založený na koroutinu. Obsahuje vnořenou strukturu „p_type“, která slouží jako typ příslibu pro koroutinu. Struktura p_type definuje funkce, které vyžaduje mašinérie coroutine, jako je get_return_object(), initial_suspend(), final_suspend(), unhandled_exception() a return_void(). Struktura p_type také obsahuje funkci yield_value(int value), která se používá k získání hodnot z korutiny. Přidá zadanou hodnotu k vektoru hodnot.

Struktura NEWCoroutine obsahuje členskou proměnnou std::vector s názvem „values“, která představuje vygenerované hodnoty. Uvnitř NEWCoroutine je iterátor vnořených struktur, který umožňuje iterovat generované hodnoty. Obsahuje coro_handle, což je popisovač koroutiny a definuje operátory jako !=, ++ a * pro iteraci.

Pomocí funkce begin() vytvoříme iterátor na začátku coroutine získáním coro_handle ze slibu p_type. Zatímco funkce end() vytváří iterátor, který představuje konec coroutine a je konstruován pomocí nullptr coro_handle. Poté se funkce slib() použije k vrácení typu slibu vytvořením coroutine_handle ze slibu p_type. Funkce createNumbers() je rutina, která poskytuje tři hodnoty – 5, 6 a 7 – pomocí klíčového slova co_yield.

Ve funkci main() je instance NEWCoroutine s názvem „nc“ vytvořena vyvoláním korutiny generationNumbers(). Tím se koroutin inicializuje a zachytí jeho stav. Smyčka „for“ založená na rozsahu se používá k iteraci hodnot „nc“ a každá hodnota je vytištěna, které jsou odděleny mezerou pomocí std::cout.

Vygenerovaný výstup je následující:

Závěr

Tento článek demonstruje využití korutin v C++. Probrali jsme dva příklady. Pro první ilustraci je základní koroutina vytvořena v programu C++ pomocí funkcí coroutine. Zatímco druhá demonstrace byla provedena s využitím korutin s parametry a poskytnutím generování chování podobného generátoru pro vytvoření posloupnosti čísel.