На самом деле приведенный вами пример показывает различия, если вы используете довольно длинную функцию, такую как
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
Пакетная задача
Сам по себе A packaged_task
не запускается, вам нужно вызвать его:
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
С другой стороны, std::async
with launch::async
будет пытаться запустить задачу в другом потоке:
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";
недостаток
Но прежде чем пытаться использовать async
для всего, имейте в виду, что возвращенное будущее имеет особое общее состояние, которое требует, чтобы future::~future
блоки:
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;
*/
Поэтому, если вам нужна настоящая асинхронность, вам нужно сохранить возвращаемое future
, или если вам не нужен результат, если обстоятельства изменятся:
{
auto pizza = std::async(get_pizza);
/* ... */
if(need_to_go)
return; // ~future will block
else
eat(pizza.get());
}
Для получения дополнительной информации по этому вопросу см статья Герба Саттера async
и~future
, который описывает проблему, и Скотт Майер std::futures
из std::async
не являются специальными , которая описывает понимание. Также обратите внимание, что это поведение было указано в C ++ 14 и выше , но также обычно реализовано в C ++ 11.
Дальнейшие отличия
Используя, std::async
вы больше не можете запускать свою задачу в определенном потоке, где std::packaged_task
его можно переместить в другие потоки.
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";
Кроме того, packaged_task
перед вызовом необходимо вызвать a f.get()
, иначе программа зависнет, поскольку будущее никогда не станет готовым:
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);
TL; DR
Используйте, std::async
если вы хотите, чтобы некоторые вещи были выполнены, и вам все равно, когда они будут выполнены, и std::packaged_task
если вы хотите завершить работу, чтобы переместить их в другие потоки или вызвать их позже. Или, если процитировать Кристиана :
В конце концов, a std::packaged_task
- это просто функция более низкого уровня для реализации std::async
(поэтому она может делать больше, чем std::async
при использовании вместе с другими вещами более низкого уровня, например std::thread
). Просто изъяснялась std::packaged_task
это std::function
связано с std::future
и std::async
оберток и называет std::packaged_task
(возможно , в другом потоке).