问题描述
在使用C ++ 11的线程模型时,我注意到
std :: packed_task< int ,int)> task([](int a,int b){return a + b;});
auto f = task.get_future();
task(2,3);
std :: cout<< f.get()<< '\\\
';
和
auto f = std :: async(std :: launch :: async,
[](int a,int b){return a + b;},2,3)
std :: cout<< f.get()<< '\\\
';
似乎做同样的事情。我明白,如果我用 std :: launch :: deferred
运行 std :: async
,但是在这种情况下是有一个吗?
这两种方法有什么区别,更重要的是,在什么用例中我应该使用一个呢? / p>
实际上,刚刚给出的示例显示了如果使用相当长的函数,例如
//!睡眠一秒钟并返回1
auto sleep = [](){
std :: this_thread :: sleep_for(std :: chrono :: seconds(1));
return 1;
};
包装任务
A packed_task
无法启动它自己,你必须调用它:
std :: packaged_task< int()>任务(睡眠);
auto f = task.get_future();
task(); //调用函数
//你必须等待任务返回。由于任务调用sleep
//你将不得不等待至少1秒钟。
std :: cout<< 你可以看到这之后1秒\\\
;
//但是,f.get()将可用,因为任务已经完成。
std :: cout<< f.get()<< std :: endl;
std :: async
另一方面, std :: async
与 launch :: async
将尝试在不同的线程中运行任务:
auto f = std :: async异步,睡眠);
std :: cout<< 你可以立即看到!\\\
;
//但是,未来的值将在睡眠完成后可用
//因此f.get()可以阻止1秒钟。
std :: cout<< f.get()<< 这将在一秒后显示!\\\
;
缺点
请记住,返回的未来有一个特殊的共享状态,它要求 future ::〜future $ c $> c> blocks:
std :: async(do_work1); //〜future blocks
std :: async(do_work2); //〜future blocks
/ * output:(假设do_work *记录他们的进度)
do_work1()开始;
do_work1()stopped;
do_work2()开始;
do_work2()stopped;
* /
所以如果你想真正的异步,你需要保留返回的 future
,或者如果情况改变时您不关心结果:
{
auto pizza = std :: async(get_pizza);
/ * ... * /
if(need_to_go)
return; //〜future will block
else
eat(pizza.get());有关这方面的更多信息,请参阅Herb Sutter的文章,以及Scott Meyer的,
更多差异
使用 std :: async
你不能在一个特定的线程上运行你的任务, std :: packed_task
可以移动到其他线程。
std :: packaged_task< int(int,int)>任务(...);
auto f = task.get_future();
std :: thread myThread(std :: move(task),2,3);
std :: cout<< f.get()<< \\\
;
此外,还需要调用 packaged_task
之前调用 f.get()
,否则程序将冻结,因为未来将永远不会准备:
std :: packaged_task< int(int,int)>任务(...);
auto f = task.get_future();
std :: cout<< f.get()<< \\\
; //哎呀!
task(2,3);
TL; DR
使用 std :: async
如果你想要一些事情做完,并不在乎他们完成后,和 std :: packed_task
如果你想包装的东西,以便将它们移动到其他线程或稍后调用它们。或者,引用:
While working with the threaded model of C++11, I noticed that
std::packaged_task<int(int,int)> task([](int a, int b) { return a + b; });
auto f = task.get_future();
task(2,3);
std::cout << f.get() << '\n';
and
auto f = std::async(std::launch::async,
[](int a, int b) { return a + b; }, 2, 3);
std::cout << f.get() << '\n';
seem to do exactly the same thing. I understand that there could be a major difference if I ran std::async
with std::launch::deferred
, but is there one in this case?
What is the difference between these two approaches, and more importantly, in what use cases should I use one over the other?
解决方案 Actually the example you just gave shows the differences if you use a rather long function, such as
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
Packaged task
A packaged_task
won't start on it's own, you have to invoke it:
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
On the other hand, std::async
with launch::async
will try to run the task in a different thread:
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";
Drawback
But before you try to use async
for everything, keep in mind that the returned future has a special shared state, which demands that future::~future
blocks:
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;
*/
So if you want real asynchronous you need to keep the returned future
, or if you don't care for the result if the circumstances change:
{
auto pizza = std::async(get_pizza);
/* ... */
if(need_to_go)
return; // ~future will block
else
eat(pizza.get());
}
For more information on this, see Herb Sutter's article async
and ~future
, which describes the problem, and Scott Meyer's std::futures
from std::async
aren't special, which describes the insights.
Further differences
By using std::async
you cannot run your task on a specific thread anymore, where std::packaged_task
can be moved to other threads.
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";
Also, a packaged_task
needs to be invoked before you call f.get()
, otherwise you program will freeze as the future will never become ready:
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);
TL;DR
Use std::async
if you want some things done and don't really care when they're done, and std::packaged_task
if you want to wrap up things in order to move them to other threads or call them later. Or, to quote Christian:
这篇关于packed_task和async之间的区别是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!