W rzeczywistości podany przykład pokazuje różnice, jeśli używasz dość długiej funkcji, takiej jak
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
Zadanie w pakiecie
packaged_taskNie rozpocznie się swoją własną, trzeba ją wywołać:
std::packaged_task<int()> task(sleep);
auto f = task.get_future();
task();
std::cout << "You can see this after 1 second\n";
std::cout << f.get() << std::endl;
std::async
Z drugiej strony, std::asyncwith launch::asyncspróbuje uruchomić zadanie w innym wątku:
auto f = std::async(std::launch::async, sleep);
std::cout << "You can see this immediately!\n";
std::cout << f.get() << "This will be shown after a second!\n";
Wada
Ale zanim spróbujesz użyć asyncdo wszystkiego, pamiętaj, że zwrócona przyszłość ma specjalny stan współdzielony, który wymaga future::~futureblokowania:
std::async(do_work1);
std::async(do_work2);
Więc jeśli chcesz mieć rzeczywistą asynchroniczność, musisz zachować zwracany wynik futurelub jeśli nie obchodzi Cię wynik, jeśli zmienią się okoliczności:
{
auto pizza = std::async(get_pizza);
if(need_to_go)
return;
else
eat(pizza.get());
}
Aby uzyskać więcej informacji na ten temat, zobacz artykuł Herba Suttera asynci~future , który opisuje problem, oraz Scott Meyer std::futuresz std::asyncnie są specjalne , który opisuje spostrzeżenia. Zwróć także uwagę, że to zachowanie zostało określone w C ++ 14 i nowszych , ale jest również powszechnie zaimplementowane w C ++ 11.
Dalsze różnice
Korzystając z niego std::async, nie możesz już uruchamiać zadania na określonym wątku, skąd std::packaged_taskmożna je przenieść do innych wątków.
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";
Ponadto packaged_tasknależy wywołać a przed wywołaniem f.get(), w przeciwnym razie program zawiesi się, ponieważ przyszłość nigdy nie będzie gotowa:
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n";
task(2,3);
TL; DR
Użyj, std::asyncjeśli chcesz, aby coś zostało zrobione i nie obchodzi std::packaged_taskcię, kiedy są zrobione, i jeśli chcesz podsumować rzeczy, aby przenieść je do innych wątków lub zadzwonić później. Lub cytując Christiana :
Ostatecznie a std::packaged_taskjest po prostu funkcją niższego poziomu do zaimplementowania std::async(dlatego może zdziałać więcej niż w std::asyncpołączeniu z innymi elementami niższego poziomu, takimi jak std::thread). Po prostu wymówione a std::packaged_taskjest std::functionpołączeniem z a std::futureoraz std::asynczawija i wywołuje std::packaged_task(prawdopodobnie w innym wątku).