Sebenarnya contoh yang baru saja Anda berikan menunjukkan perbedaan jika Anda menggunakan fungsi yang agak panjang, seperti
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
Tugas yang dikemas
A packaged_task
tidak akan memulai sendiri, Anda harus memohonnya:
std::packaged_task<int()> task(sleep);
auto f = task.get_future();
task(); // invoke the function
// You have to wait until task returns. Since task calls sleep
// you will have to wait at least 1 second.
std::cout << "You can see this after 1 second\n";
// However, f.get() will be available, since task has already finished.
std::cout << f.get() << std::endl;
std::async
Di sisi lain, std::async
dengan launch::async
akan mencoba menjalankan tugas di utas berbeda:
auto f = std::async(std::launch::async, sleep);
std::cout << "You can see this immediately!\n";
// However, the value of the future will be available after sleep has finished
// so f.get() can block up to 1 second.
std::cout << f.get() << "This will be shown after a second!\n";
Kekurangan
Tetapi sebelum Anda mencoba menggunakan async
untuk semuanya, perlu diingat bahwa masa depan yang dikembalikan memiliki keadaan bersama yang khusus, yang menuntut yang future::~future
menghalangi:
std::async(do_work1); // ~future blocks
std::async(do_work2); // ~future blocks
/* output: (assuming that do_work* log their progress)
do_work1() started;
do_work1() stopped;
do_work2() started;
do_work2() stopped;
*/
Jadi, jika Anda ingin sinkron nyata, Anda harus tetap mengembalikannya future
, atau jika Anda tidak peduli dengan hasilnya jika keadaan berubah:
{
auto pizza = std::async(get_pizza);
/* ... */
if(need_to_go)
return; // ~future will block
else
eat(pizza.get());
}
Untuk informasi lebih lanjut tentang ini, lihat artikel Herb Sutter async
dan~future
, yang menjelaskan masalahnya, dan Scott Meyer std::futures
dari std::async
tidak khusus , yang menjelaskan wawasan. Perhatikan juga bahwa perilaku ini ditentukan dalam C ++ 14 dan lebih tinggi , tetapi juga umum diimplementasikan dalam C ++ 11.
Perbedaan lebih lanjut
Dengan menggunakan std::async
Anda tidak dapat menjalankan tugas Anda pada utas tertentu lagi, di mana std::packaged_task
dapat dipindahkan ke utas lainnya.
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::thread myThread(std::move(task),2,3);
std::cout << f.get() << "\n";
Juga, packaged_task
perlu dipanggil sebelum Anda menelepon f.get()
, jika tidak, program Anda akan macet karena masa depan tidak akan pernah siap:
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);
TL; DR
Gunakan std::async
jika Anda ingin beberapa hal selesai dan tidak benar-benar peduli ketika sudah selesai, dan std::packaged_task
jika Anda ingin menyelesaikannya untuk memindahkannya ke utas lain atau hubungi mereka nanti. Atau, mengutip Christian :
Pada akhirnya a std::packaged_task
hanyalah fitur level yang lebih rendah untuk implementasi std::async
(itulah sebabnya ia dapat melakukan lebih banyak daripada std::async
jika digunakan bersama dengan hal-hal level rendah lainnya, seperti std::thread
). Secara sederhana a std::packaged_task
adalah std::function
tautan ke a std::future
dan std::async
membungkus dan memanggil a std::packaged_task
(mungkin di utas yang berbeda).
std::packaged_task
hanyalah fitur level yang lebih rendah untuk implementasistd::async
(itulah sebabnya ia dapat melakukan lebih banyak daripadastd::async
jika digunakan bersama dengan hal-hal level rendah lainnya, sepertistd::thread
). Secara sederhana astd::packaged_task
adalahstd::function
tautan ke astd::future
danstd::async
membungkus dan memanggil astd::packaged_task
(mungkin di utas yang berbeda).Paket Tugas vs async
p> Tugas terpaket memiliki tugas
[function or function object]
dan pasangan masa depan / janji. Saat tugas mengeksekusi pernyataan kembali, hal itu menyebabkanset_value(..)
padapackaged_task
's janji.a> Diberikan Masa Depan, janji dan tugas paket kita dapat membuat tugas-tugas sederhana tanpa terlalu khawatir tentang utas [utas hanyalah sesuatu yang kita berikan untuk menjalankan tugas].
Namun kita perlu mempertimbangkan berapa banyak utas untuk digunakan atau apakah tugas paling baik dijalankan pada utas saat ini atau pada yang lain dll. Keputusan semacam itu dapat ditangani oleh peluncur utas yang disebut
async()
, yang memutuskan apakah akan membuat utas baru atau mendaur ulang yang lama satu atau cukup jalankan tugas di utas saat ini. Ia mengembalikan masa depan.sumber
sumber