实际上你刚才给出的例子显示了如果你使用一个相当长的函数,比如
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
打包任务
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 和 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());
}
有关这方面的更多信息,请参阅描述问题的 Herb Sutter 的文章 async and ~future 和描述见解的 Scott Meyer 的 std::futures from std::async aren't special。还要注意这种行为was specified in C++14 and up,但也通常在 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";
另外,在调用f.get() 之前需要调用packaged_task,否则你的程序将冻结,因为未来永远不会准备好:
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。或者,引用Christian:
最后,std::packaged_task 只是实现std::async 的较低级别功能(这就是为什么如果与其他较低级别的东西一起使用,它可以做的比std::async 更多,例如std::thread)。简单地说,std::packaged_task 是一个链接到 std::future 的 std::function 和 std::async 包装并调用 std::packaged_task(可能在不同的线程中)。