Contoh C++ Coroutines

Contoh C Coroutines



Coroutines menyediakan ciri bahasa yang membolehkan anda menulis kod tak segerak dalam cara yang lebih teratur dan linear, mempromosikan pendekatan berstruktur dan berjujukan. Mereka memberikan mekanisme untuk menjeda dan memulakan semula pelaksanaan fungsi pada keadaan tertentu tanpa menghentikan keseluruhan utas. Coroutine membantu apabila mengendalikan tugas yang memerlukan menunggu operasi I/O seperti membaca daripada fail atau menghantar panggilan rangkaian.

Coroutines adalah berdasarkan konsep penjana di mana fungsi boleh menghasilkan nilai dan kemudiannya disambung semula untuk meneruskan pelaksanaan. Coroutines menyediakan alat yang berkuasa untuk mengurus operasi tak segerak dan boleh meningkatkan kualiti keseluruhan kod anda.

Kegunaan Coroutines

Coroutine diperlukan untuk beberapa sebab dalam pengaturcaraan moden, terutamanya dalam bahasa seperti C++. Berikut ialah beberapa sebab utama mengapa coroutine bermanfaat:







Coroutines menyediakan penyelesaian yang elegan kepada pengaturcaraan tak segerak. Mereka memungkinkan untuk membuat kod yang kelihatan berurutan dan menyekat yang lebih mudah untuk difikirkan dan difahami. Coroutine boleh menangguhkan pelaksanaan mereka pada titik tertentu tanpa menyekat benang, membolehkan operasi selari tugas lain. Oleh sebab itu, sumber sistem boleh digunakan dengan lebih berkesan, dan tindak balas dipertingkatkan dalam aplikasi yang melibatkan operasi I/O atau menunggu peristiwa luaran.



Mereka mungkin menjadikan kod lebih mudah difahami dan diselenggara. Dengan menghapuskan rantai panggil balik kompleks atau mesin keadaan, coroutine membolehkan kod ditulis dalam gaya yang lebih linear dan berjujukan. Ini menambah baik organisasi kod, mengurangkan sarang dan menjadikan logik mudah difahami.



Coroutine menyediakan cara berstruktur untuk mengendalikan konkurensi dan selari. Ia membolehkan anda menyatakan corak penyelarasan kompleks dan aliran kerja tak segerak menggunakan sintaks yang lebih intuitif. Tidak seperti model benang tradisional di mana benang mungkin disekat, coroutine boleh membebaskan sumber sistem dan membolehkan multitugas yang cekap.





Mari cipta beberapa contoh untuk menunjukkan pelaksanaan coroutine dalam C++.

Contoh 1: Coroutine Asas

Contoh coroutine asas disediakan dalam perkara berikut:



#include

#include

struct Corout ini {

struct promise_type {

ThisCorout get_return_object ( ) { kembali { } ; }

std :: suspend_never initial_suspend ( ) { kembali { } ; }

std :: suspend_never penangguhan_akhir ( ) tidak kecuali { kembali { } ; }

batal unhandled_exception ( ) { }

batal return_void ( ) { }

} ;

bool tunggu_sedia ( ) { kembali salah ; }

batal tunggu_gantung ( std :: coroutine_handle <> h ) { }

batal tunggu_sambung semula ( ) { std :: cout << 'Coroutine disambung semula.' << std :: endl ; }

} ;

ThisCorout foo ( ) {

std :: cout << 'Coroutine telah bermula.' << std :: endl ;

bersama_menunggu std :: gantung_selalu { } ;

co_return ;

}

int utama ( ) {

auto cr = foo ( ) ;

std :: cout << 'Coroutine dicipta.' << std :: endl ;

cr. tunggu_sambung semula ( ) ;

std :: cout << 'Coroutine selesai.' << std :: endl ;

kembali 0 ;

}

Mari lihat kod yang disediakan sebelum ini dan terangkan secara terperinci:

Selepas memasukkan fail pengepala yang diperlukan, kami mentakrifkan struct 'ThisCorout' yang mewakili coroutine. Di dalam 'ThisCorout', satu lagi struct iaitu 'promise_type' ditakrifkan yang mengendalikan janji coroutine. Struktur ini menyediakan pelbagai fungsi yang diperlukan oleh jentera coroutine.

Di dalam kurungan, kami menggunakan fungsi get_return_object(). Ia mengembalikan objek coroutine itu sendiri. Dalam keadaan ini, ia mengembalikan objek 'ThisCorout' kosong. Kemudian, fungsi initial_suspend() digunakan yang menentukan tingkah laku apabila coroutine mula-mula dimulakan. Std::suspend_never bermaksud coroutine tidak seharusnya digantung pada mulanya.

Selepas itu, kita mempunyai fungsi final_suspend() yang menentukan tingkah laku apabila coroutine hampir selesai. Std::suspend_never bermaksud coroutine tidak seharusnya digantung sebelum pemuktamadnya.

Jika coroutine melemparkan pengecualian, kaedah unhandled_exception() akan digunakan. Dalam contoh ini, ia adalah fungsi kosong, tetapi anda boleh mengendalikan pengecualian seperti yang diperlukan. Apabila coroutine ditamatkan tanpa menghasilkan nilai, kaedah return_void() digunakan. Dalam kes ini, ia juga merupakan fungsi kosong.

Kami juga mentakrifkan tiga fungsi ahli dalam 'ThisCorout'. Fungsi await_ready() dipanggil untuk menyemak sama ada coroutine bersedia untuk menyambung semula pelaksanaan. Dalam contoh ini, ia sentiasa mengembalikan palsu yang menunjukkan bahawa coroutine tidak bersedia untuk menyambung semula serta-merta. Apabila coroutine akan digantung, kaedah await_suspend() dipanggil. Di sini, ia adalah fungsi kosong yang bermaksud tiada penggantungan diperlukan. Program ini memanggil await_resume() apabila coroutine disambung semula selepas penggantungan. Ia hanya mengeluarkan mesej yang menyatakan bahawa coroutine telah disambung semula.

Baris seterusnya kod mentakrifkan foo() fungsi coroutine. Di dalam foo(), kita mulakan dengan mencetak mesej yang menyatakan bahawa coroutine telah bermula. Kemudian, co_await std::suspend_always{} digunakan untuk menggantung coroutine dan menunjukkan bahawa ia boleh disambung semula pada satu masa kemudian. Pernyataan co_return digunakan untuk menyelesaikan coroutine tanpa mengembalikan sebarang nilai.

Dalam fungsi main(), kami membina objek 'cr' jenis 'ThisCorout' dengan memanggil foo(). Ini mencipta dan memulakan coroutine. Kemudian, mesej yang menyatakan bahawa coroutine telah dibuat dicetak. Seterusnya, kami memanggil await_resume() pada objek coroutine 'cr' untuk menyambung semula pelaksanaannya. Di dalam await_resume(), mesej 'The Coroutine is resumed' dicetak. Akhir sekali, kami memaparkan mesej yang menyatakan bahawa coroutine selesai sebelum program ditamatkan.

Apabila anda menjalankan program ini, output adalah seperti berikut:

Contoh 2: Coroutine dengan Parameter dan Hasil

Sekarang, untuk ilustrasi ini, kami menyediakan kod yang menunjukkan penggunaan coroutine dengan parameter dan menghasilkan dalam C++ untuk mencipta gelagat seperti penjana untuk menghasilkan jujukan nombor.

#include

#include

#include

struct NEWCoroutine {

struct p_type {

std :: vektor < int > nilai ;

NEWCoroutine get_return_object ( ) { kembali { } ; }

std :: gantung_selalu initial_suspend ( ) { kembali { } ; }

std :: gantung_selalu penangguhan_akhir ( ) tidak kecuali { kembali { } ; }

batal unhandled_exception ( ) { }

batal return_void ( ) { }

std :: gantung_selalu nilai_hasil ( int nilai ) {

nilai. menolak kembali ( nilai ) ;

kembali { } ;

}

} ;

std :: vektor < int > nilai ;

struct iterator {

std :: coroutine_handle <> chorus_handle ;

pengendali bool != ( const iterator & lain ) const { kembali chorus_handle != lain. chorus_handle ; }

iterator & pengendali ++ ( ) { chorus_handle. resume ( ) ; kembali * ini ; }

int pengendali * ( ) const { kembali chorus_handle. janji ( ) . nilai [ 0 ] ; }

} ;

iterator bermula ( ) { kembali iterator { std :: coroutine_handle < p_type >:: dari_janji ( janji ( ) ) } ; }

penghujung iterator ( ) { kembali iterator { nullptr } ; }

std :: coroutine_handle < p_type > janji ( ) { kembali
std :: coroutine_handle < p_type >:: dari_janji ( * ini ) ; }

} ;

NEWCoroutine generateNumbers ( ) {

co_yield 5 ;

co_yield 6 ;

co_yield 7 ;

}

int utama ( ) {

NEWCoroutine nc = generateNumbers ( ) ;

untuk ( int nilai : nc ) {

std :: cout << nilai << ' ' ;

}

std :: cout << std :: endl ;

kembali 0 ;

}

Dalam kod sebelumnya, struct NEWCoroutine mewakili penjana berasaskan coroutine. Ia mengandungi struct 'p_type' bersarang yang berfungsi sebagai jenis janji untuk coroutine. Struktur p_type mentakrifkan fungsi yang diperlukan oleh jentera coroutine seperti get_return_object(), initial_suspend(), final_suspend(), unhandled_exception(), dan return_void(). Struktur p_type juga termasuk fungsi yield_value(int value) yang digunakan untuk menghasilkan nilai daripada coroutine. Ia menambah nilai yang disediakan kepada vektor nilai.

Struktur NEWCoroutine termasuk pembolehubah ahli std::vector dipanggil 'nilai' yang mewakili nilai yang dijana. Di dalam NEWCoroutine, terdapat iterator struct bersarang yang membolehkan untuk melelaran ke atas nilai yang dijana. Ia memegang coro_handle yang merupakan pemegang kepada coroutine dan mentakrifkan operator seperti !=, ++, dan * untuk lelaran.

Kami menggunakan fungsi begin() untuk mencipta iterator pada permulaan coroutine dengan mendapatkan coro_handle daripada janji p_type. Manakala fungsi end() mencipta iterator yang mewakili penghujung coroutine dan dibina dengan nullptr coro_handle. Selepas itu, fungsi promise() digunakan untuk mengembalikan jenis promise dengan mencipta coroutine_handle daripada janji p_type. Fungsi generateNumbers() ialah coroutine yang menghasilkan tiga nilai – 5, 6, dan 7 – menggunakan kata kunci co_yield.

Dalam fungsi main(), contoh NEWCoroutine bernama 'nc' dicipta dengan menggunakan generateNumbers() coroutine. Ini memulakan coroutine dan menangkap keadaannya. Gelung 'untuk' berasaskan julat digunakan untuk mengulangi nilai 'nc', dan setiap nilai dicetak yang dipisahkan oleh ruang menggunakan std::cout.

Output yang dihasilkan adalah seperti berikut:

Kesimpulan

Artikel ini menunjukkan penggunaan coroutine dalam C++. Kami membincangkan dua contoh. Untuk ilustrasi pertama, coroutine asas dicipta dalam program C++ menggunakan fungsi coroutine. Manakala demonstrasi kedua dijalankan dengan menggunakan coroutine dengan parameter dan menghasilkan untuk menjana tingkah laku seperti penjana untuk mencipta urutan nombor.