实际上,如果您使用相当长的函数,您刚刚给出的示例显示了差异,例如
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
打包任务
Apackaged_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
withlaunch::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
和~future
,以及描述见解的 Scott Meyer 的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;博士
如果std::async
您想要完成某些事情并且并不真正关心它们何时完成,并且std::packaged_task
如果您想包装一些事情以便将它们移动到其他线程或稍后调用它们。或者,引用Christian的话:
最后 astd::packaged_task
只是实现的一个较低级别的功能(这就是为什么它比与其他较低级别的东西一起使用std::async
可以做更多的事情,例如)。简单地说 a是链接到 a并包装并调用 a (可能在不同的线程中)。std::async
std::thread
std::packaged_task
std::function
std::future
std::async
std::packaged_task