实际上,你刚刚举的例子展示了使用较长函数时的差异,比如...
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
封装任务
封装任务
不会自动启动,您需要调用它:
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
另一方面,std::async
与launch::async
一起使用时,会尝试在不同的线程中运行任务:
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";
缺点
但在你试图将async
用于所有情况之前,请记住返回的future具有特殊的共享状态,这要求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;
else
eat(pizza.get());
}
有关此事的更多信息,请参阅Herb Sutter的文章{{link1:
async
和
~future
}},其中描述了问题,以及Scott Meyer的文章{{link2:
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";
此外,在调用
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);
简而言之
如果你想要完成一些事情,但并不在乎它们何时完成,那就使用std::async
;如果你想要将事情封装起来以便将它们移动到其他线程或稍后调用它们,那就使用std::packaged_task
。或者,引用Christian的话:
最终,std::packaged_task
只是一个更低层次的功能,用于实现std::async
(这就是为什么它可以在与其他更低层次的东西(如std::thread
)一起使用时做更多事情)。简单来说,std::packaged_task
是一个与std::future
和std::function
相关联的东西,而std::async
则封装并调用一个std::packaged_task
(可能在不同的线程中)。
std::packaged_task
只是实现std::async
的一种更低级别的特性(这就是为什么如果与其他低级别的东西一起使用,比如std::thread
,它可以做更多的事情)。简单来说,std::packaged_task
是一个链接到std::future
的std::function
,而std::async
则包装并调用一个std::packaged_task
(可能在不同的线程中)。 - Christian Rau