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_task
Nie 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::async
with launch::async
spró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ć async
do wszystkiego, pamiętaj, że zwrócona przyszłość ma specjalny stan współdzielony, który wymaga future::~future
blokowania:
std::async(do_work1);
std::async(do_work2);
Więc jeśli chcesz mieć rzeczywistą asynchroniczność, musisz zachować zwracany wynik future
lub 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 async
i~future
, który opisuje problem, oraz Scott Meyer std::futures
z std::async
nie 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_task
moż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_task
należ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::async
jeśli chcesz, aby coś zostało zrobione i nie obchodzi std::packaged_task
cię, 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_task
jest po prostu funkcją niższego poziomu do zaimplementowania std::async
(dlatego może zdziałać więcej niż w std::async
połączeniu z innymi elementami niższego poziomu, takimi jak std::thread
). Po prostu wymówione a std::packaged_task
jest std::function
połączeniem z a std::future
oraz std::async
zawija i wywołuje std::packaged_task
(prawdopodobnie w innym wątku).