Apa yang coroutines dalam C++20?

Apa yang coroutines di [tag:C++20]?

Dalam hal apa itu yang berbeda dari "Parallelism2" atau "Concurrency2" (terlihat dalam gambar di bawah ini)?

Di bawah ini adalah gambar dari ISOCPP.

https://isocpp.org/files/img/wg21-timeline-2017-03.png

Mengomentari pertanyaan (4)
Larutan

Pada tingkat abstrak, Coroutines membagi gagasan memiliki kondisi eksekusi off dari gagasan memiliki sebuah thread eksekusi.

SIMD (single instruction multiple data) memiliki beberapa "benang eksekusi" tetapi hanya satu negara eksekusi (hanya bekerja pada beberapa data). Bisa dibilang algoritma paralel adalah bit seperti ini, bahwa anda memiliki satu "program" berjalan pada data yang berbeda.

Threading memiliki beberapa "benang eksekusi" dan beberapa eksekusi serikat. Anda memiliki lebih dari satu program, dan lebih dari satu thread eksekusi.

Coroutines memiliki beberapa eksekusi serikat, tetapi tidak memiliki benang eksekusi. Anda memiliki sebuah program, dan program negara, tetapi tidak memiliki benang eksekusi.


Contoh yang paling mudah coroutines adalah generator atau enumerables dari bahasa lain.

Dalam pseudo code:

function Generator() {
  for (i = 0 to 100)
    produce i
}

The Generator yang disebut, dan pertama kalinya ia dipanggil kembali 0. Negara dikenang (berapa banyak negara bervariasi dengan pelaksanaan coroutines), dan waktu berikutnya anda sebut itu terus mana ia tinggalkan. Jadi kembali 1 waktu berikutnya. Kemudian 2.

Akhirnya mencapai akhir dari loop dan jatuh akhir fungsi; coroutine selesai. (Apa yang terjadi di sini bervariasi berdasarkan bahasa yang kita bicarakan; di python, melempar pengecualian).

Coroutines membawa kemampuan ini untuk C++.

Ada dua jenis coroutines; stackful dan stackless.

Sebuah stackless coroutine hanya toko-toko lokal variabel dalam keadaan dan lokasi eksekusi.

Sebuah stackful coroutine toko-toko seluruh stack (seperti benang).

Stackless coroutines bisa sangat ringan. Usulan terakhir yang saya baca yang terlibat pada dasarnya menulis ulang fungsi anda menjadi sesuatu yang sedikit seperti lambda; semua variabel lokal pergi ke state dari sebuah objek, dan label yang digunakan untuk melompat ke/dari lokasi di mana coroutine "menghasilkan" hasil antara.

Proses yang menghasilkan suatu nilai yang disebut "hasil", sebagai coroutines adalah sedikit seperti koperasi multithreading; anda menghasilkan titik eksekusi kembali ke pemanggil.

Meningkatkan pelaksanaan stackful coroutines; ini memungkinkan anda memanggil fungsi untuk menghasilkan untuk anda. Stackful coroutines yang lebih kuat, tapi juga lebih mahal.


Ada lebih untuk coroutines dari generator sederhana. Anda dapat menunggu coroutine di coroutine, yang memungkinkan anda menulis coroutines dalam cara yang berguna.

Coroutines, seperti if, loop dan fungsi panggilan, adalah jenis lain dari "terstruktur goto" yang memungkinkan anda untuk mengekspresikan tertentu yang berguna pola (seperti keadaan mesin) dengan cara yang lebih alami.


Khusus pelaksanaan Coroutines dalam C++ adalah sedikit menarik.

Pada tingkat yang paling dasar, ia menambahkan beberapa kata kunci ke C++: co_return co_await co_yield, bersama-sama dengan beberapa jenis perpustakaan yang bekerja dengan mereka.

Fungsi menjadi coroutine dengan memiliki salah satu dari mereka di tubuhnya. Jadi dari pernyataan mereka dibedakan dari fungsi.

Ketika salah satu dari mereka tiga kata kunci yang digunakan dalam sebuah fungsi tubuh, beberapa standar yang diamanatkan memeriksa kembali jenis dan argumen-argumen yang terjadi dan fungsi berubah menjadi coroutine. Ini memeriksa memberitahu compiler mana untuk menyimpan fungsi keadaan ketika fungsi ini ditangguhkan.

Yang paling sederhana coroutine adalah generator:

generator get_integers( int start=0, int step=1 ) {
  for (int current=start; true; current+= step)
    co_yield current;
}

co_yield menunda fungsi eksekusi, toko-toko negara itu di generator<int>, kemudian mengembalikan nilai saat ini melalui generator<int>.

Anda dapat loop di atas bilangan bulat kembali.

co_await sementara memungkinkan anda sambatan satu coroutine ke yang lain. Jika anda berada di salah satu coroutine dan anda perlu hasil awaitable hal yang (sering coroutine) sebelum maju, anda co_await di atasnya. Jika mereka siap, anda melanjutkan dengan segera; jika tidak, anda menangguhkan sampai awaitable anda sedang menunggu siap.

std::future load_data( std::string resource )
{
  auto handle = co_await open_resouce(resource);
  while( auto line = co_await read_line(handle)) {
    if (std::optional r = parse_data_from_line( line ))
       co_return *r;
  }
  co_return std::unexpected( resource_lacks_data(resource) );
}

load_data adalah coroutine yang menghasilkan std::masa depan ketika bernama sumber daya dibuka dan kita berhasil mengurai ke titik di mana kami menemukan data yang diminta.

open_resource dan read_line ini mungkin async coroutines yang membuka file dan membaca baris dari itu. Theco_awaitmenghubungkan menangguhkan dan siap keadaanload_data` untuk kemajuan mereka.

C++ coroutines jauh lebih fleksibel daripada ini, karena mereka diimplementasikan sebagai satu set minimal fitur bahasa di atas user-space jenis. Pengguna-jenis ruang secara efektif menentukan apa yang co_return co_await dan co_yield berarti -- I've melihat orang-orang yang menggunakannya untuk melaksanakan monadic opsional ekspresi seperti itu co_await pada kosong opsional otomatis propogates keadaan kosong ke luar opsional:

modified_optional add( modified_optional a, modified_optional b ) {
  return (co_await a) + (co_await b);
}

bukan

std::optional add( std::optional a, std::optional b ) {
  if (!a) return std::nullopt;
  if (!b) return std::nullopt;
  return *a + *b;
}
Komentar (11)

Sebuah coroutine seperti C fungsi yang telah kembali beberapa pernyataan dan ketika dipanggil 2 kali tidak memulai pelaksanaan di mulai dari fungsi tetapi pada instruksi pertama setelah sebelumnya dijalankan kembali. Ini lokasi eksekusi disimpan bersama-sama dengan semua otomatis variabel-variabel yang akan hidup pada stack di non coroutine fungsi.

Sebelumnya eksperimental coroutine implementasi dari Microsoft tidak menggunakan disalin tumpukan sehingga anda bahkan bisa kembali dari dalam fungsi bersarang. Tetapi versi ini ditolak oleh C++ panitia. Anda bisa mendapatkan implementasi ini misalnya dengan Meningkatkan serat perpustakaan.

Komentar (0)

coroutines seharusnya (di C++) fungsi yang mampu "tunggu" untuk beberapa rutin lainnya untuk menyelesaikan dan memberikan apapun yang dibutuhkan untuk ditangguhkan, ditunda, menunggu, rutin untuk pergi. fitur yang paling menarik untuk C++ adalah orang-orang yang coroutines idealnya akan mengambil tidak ada ruang stack...C# sudah bisa melakukan sesuatu seperti ini dengan menunggu dan yield tapi C++ mungkin harus dibangun kembali untuk mendapatkannya.

konkurensi adalah sangat terfokus pada pemisahan kekhawatiran di mana perhatian adalah tugas bahwa program ini seharusnya untuk menyelesaikan. pemisahan ini masalah dapat dilakukan dengan sejumlah cara...yang biasanya menjadi delegasi dari beberapa macam. ide concurrency adalah bahwa sejumlah proses bisa berjalan secara independen (separation of concerns) dan 'pendengar' akan langsung apa pun yang dihasilkan oleh orang-orang yang dipisahkan menyangkut ke mana ia harus pergi. ini sangat bergantung pada beberapa jenis asinkron manajemen. Ada sejumlah pendekatan untuk concurrency termasuk Aspek pemrograman berorientasi dan lain-lain. C# memiliki 'mendelegasikan' operator yang bekerja cukup baik.

paralelisme terdengar seperti concurrency dan mungkin terlibat, tetapi sebenarnya adalah membangun fisik yang melibatkan banyak prosesor diatur dalam lebih atau kurang secara paralel dengan perangkat lunak yang dapat langsung porsi dari kode untuk prosesor yang berbeda di mana ia akan berjalan dan hasilnya akan diterima kembali serentak.

Komentar (1)