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).