实际上,您刚才给出的示例显示了使用较长函数(例如,
//! 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;
*/
因此,如果您想要真正的异步,则需要保留return 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
from 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
)一起使用还能做更多的事情的原因。简单地说,a std::packaged_task
是std::function
与a的链接,std::future
并std::async
包装和调用a std::packaged_task
(可能在其他线程中)。