Ini terkait longgar dengan pertanyaan ini: Apakah std :: thread dikumpulkan dalam C ++ 11? . Meskipun pertanyaannya berbeda, tujuannya tetap sama:
Pertanyaan 1: Apakah masih masuk akal untuk menggunakan kumpulan utas Anda sendiri (atau pustaka pihak ketiga) untuk menghindari pembuatan utas yang mahal?
Kesimpulan dalam pertanyaan lain adalah bahwa Anda tidak dapat mengandalkan std::thread
untuk dikumpulkan (mungkin atau tidak). Namun, std::async(launch::async)
tampaknya memiliki peluang yang jauh lebih tinggi untuk dikumpulkan.
Ini tidak berpikir bahwa itu dipaksakan oleh standar, tetapi IMHO saya berharap bahwa semua implementasi C ++ 11 yang baik akan menggunakan penggabungan benang jika pembuatan utas lambat. Hanya pada platform di mana tidak mahal untuk membuat utas baru, saya berharap mereka selalu menelurkan utas baru.
Pertanyaan 2: Ini hanya yang saya pikirkan, tapi saya tidak punya fakta untuk membuktikannya. Saya mungkin salah besar. Apakah ini tebakan terpelajar?
Akhirnya, di sini saya telah memberikan beberapa kode contoh yang pertama menunjukkan bagaimana menurut saya pembuatan utas dapat diekspresikan oleh async(launch::async)
:
Contoh 1:
thread t([]{ f(); });
// ...
t.join();
menjadi
auto future = async(launch::async, []{ f(); });
// ...
future.wait();
Contoh 2: Aktifkan dan lupakan utas
thread([]{ f(); }).detach();
menjadi
// a bit clumsy...
auto dummy = async(launch::async, []{ f(); });
// ... but I hope soon it can be simplified to
async(launch::async, []{ f(); });
Pertanyaan 3: Apakah Anda lebih suka async
versinya daripada thread
versinya?
Selebihnya bukan lagi bagian dari pertanyaan, tetapi hanya untuk klarifikasi:
Mengapa nilai yang dikembalikan harus ditetapkan ke variabel dummy?
Sayangnya, gaya standar C ++ 11 saat ini yang Anda tangkap nilai kembaliannya std::async
, karena jika tidak destruktor akan dieksekusi, yang memblokir hingga tindakan dihentikan. Ini oleh beberapa orang dianggap sebagai kesalahan dalam standar (misalnya, oleh Herb Sutter).
Contoh dari cppreference.com ini menggambarkannya dengan baik:
{
std::async(std::launch::async, []{ f(); });
std::async(std::launch::async, []{ g(); }); // does not run until f() completes
}
Klarifikasi lain:
Saya tahu bahwa kumpulan utas mungkin memiliki kegunaan lain yang sah tetapi dalam pertanyaan ini saya hanya tertarik pada aspek menghindari biaya pembuatan utas yang mahal .
Saya pikir masih ada situasi di mana kumpulan utas sangat berguna, terutama jika Anda membutuhkan lebih banyak kontrol atas sumber daya. Misalnya, server mungkin memutuskan untuk menangani hanya sejumlah permintaan tetap secara bersamaan untuk menjamin waktu respons yang cepat dan untuk meningkatkan prediktabilitas penggunaan memori. Kolam benang seharusnya baik-baik saja, di sini.
Variabel lokal-utas juga dapat menjadi argumen untuk kumpulan utas Anda sendiri, tetapi saya tidak yakin apakah itu relevan dalam praktiknya:
- Membuat thread baru
std::thread
dimulai tanpa variabel thread-lokal yang diinisialisasi. Mungkin ini bukan yang Anda inginkan. - Dalam utas yang ditelurkan oleh
async
, itu agak tidak jelas bagi saya karena utas tersebut dapat digunakan kembali. Dari pemahaman saya, variabel lokal-thread tidak dijamin akan disetel ulang, tetapi saya mungkin salah. - Sebaliknya, menggunakan kumpulan utas Anda sendiri (ukuran tetap) memberi Anda kendali penuh jika Anda benar-benar membutuhkannya.
std::async()
. Saya masih penasaran untuk melihat bagaimana mereka mendukung destruktor thread_local non-sepele di kumpulan utas.
launch::async
maka ia memperlakukannya seolah-olah hanya launch::deferred
dan tidak pernah menjalankannya secara asinkron - jadi pada dasarnya, versi libstdc ++ itu "memilih" untuk selalu menggunakan deferred kecuali dipaksa sebaliknya.
std::async
bisa menjadi hal yang indah untuk kinerja - itu bisa menjadi sistem eksekusi tugas yang berjalan pendek standar, yang secara alami didukung oleh kumpulan utas. Saat ini, hanya std::thread
dengan beberapa omong kosong yang ditempelkan untuk membuat fungsi utas dapat mengembalikan nilai. Oh, dan mereka menambahkan fungsi "ditangguhkan" yang berlebihan yang tumpang tindih dengan tugas std::function
sepenuhnya.
std::async(launch::async)
tampaknya memiliki peluang yang jauh lebih tinggi untuk dikumpulkan." Tidak, saya yakin itustd::async(launch::async | launch::deferred)
yang mungkin dikumpulkan. Dengan hanyalaunch::async
tugas tersebut seharusnya diluncurkan di utas baru terlepas dari tugas lain apa yang sedang berjalan. Dengan adanya kebijakan tersebutlaunch::async | launch::deferred
maka pelaksana dapat memilih kebijakan yang mana, namun yang lebih penting adalah penundaan pemilihan kebijakan yang mana. Artinya, itu bisa menunggu hingga utas di kumpulan utas tersedia dan kemudian memilih kebijakan asinkron.