C++ packaged_task 和 async 有什么区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18143661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:45:11  来源:igfitidea点击:

What is the difference between packaged_task and async

c++multithreadingc++11stdasyncpackaged-task

提问by nijansen

While working with the threaded model of C++11, I noticed that

在使用 C++11 的线程模型时,我注意到

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::asyncwith std::launch::deferred, but is there one in this case?

似乎做完全一样的事情。我知道如果我std::async使用std::launch::deferred,可能会有很大的不同,但在这种情况下有没有?

What is the difference between these two approaches, and more importantly, in what use cases should I use one over the other?

这两种方法之间有什么区别,更重要的是,在哪些用例中我应该使用一种方法而不是另一种方法?

回答by Zeta

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_taskwon't start on it's own, you have to invoke it:

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

On the other hand, std::asyncwith launch::asyncwill try to run the task in a different thread:

另一方面,std::asyncwithlaunch::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";

Drawback

退税

But before you try to use asyncfor everything, keep in mind that the returned future has a special shared state, which demands that future::~futureblocks:

但是在你尝试使用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;
*/

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:

因此,如果您想要真正的异步,则需要保留返回的future,或者如果情况发生变化您不关心结果:

{
    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 asyncand ~future, which describes the problem, and Scott Meyer's std::futuresfrom std::asyncaren't special, which describes the insights. Also do note that this behavior was specified in C++14 and up, but also commonly implemented in C++11.

有关更多信息,请参阅香草萨特的文章async~future,它描述了问题,和Scott Meyer的std::futures距离std::async是不是特别的,它描述了见解。另请注意,此行为是在 C++14 及更高版本中指定的,但也通常在 C++11 中实现。

Further differences

进一步的差异

By using std::asyncyou cannot run your task on a specific thread anymore, where std::packaged_taskcan be moved to other threads.

通过使用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";

Also, a packaged_taskneeds to be invoked before you call f.get(), otherwise you program will freeze as the future will never become ready:

此外,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

TL; 博士

Use std::asyncif you want some things done and don't really care when they're done, and std::packaged_taskif you want to wrap up things in order to move them to other threads or call them later. Or, to quote Christian:

使用std::async,如果你想一些事情做,他们就完成了的时候真的不关心,而且std::packaged_task如果你想包裹起来的东西,以便将它们移动到其他线程或以后打电话给他们。或者,引用Christian 的话

In the end a std::packaged_taskis just a lower level feature for implementing std::async(which is why it can do more than std::asyncif used together with other lower level stuff, like std::thread). Simply spoken a std::packaged_taskis a std::functionlinked to a std::futureand std::asyncwraps and calls a std::packaged_task(possibly in a different thread).

最后, astd::packaged_task只是用于实现的较低级别的功能std::async(这就是为什么它可以比std::async与其他较低级别的东西一起使用时做得更多,例如std::thread)。简单地说 astd::packaged_task是一个std::function链接到 astd::futurestd::async包装和调用 a std::packaged_task(可能在不同的线程中)。

回答by nijansen

Packaged Task vs async

打包任务与异步

p>Packaged task holds a task [function or function object]and future/promise pair. When the task executes a return statement, it causes set_value(..)on the packaged_task's promise.

p>打包任务包含任务[function or function object]和未来/承诺对。执行任务时return语句,它会导致set_value(..)packaged_task所做的承诺。

a>Given Future, promise and package task we can create simple tasks without worrying too much about threads [thread is just something we give to run a task].

a>鉴于 Future、promise 和 package task,我们可以创建简单的任务,而无需过多担心线程 [线程只是我们为运行任务而提供的东西]。

However we need to consider how many threads to use or whether a task is best run on the current thread or on another etc.Such descisions can be handled by a thread launcher called async(), that decides whether to create a new a thread or recycle an old one or simply run the task on the current thread. It returns a future .

然而,我们需要考虑使用多少线程或者任务是最好在当前线程上运行还是在另一个线程上运行等等。此类决策可以由称为 的线程启动器处理,该启动器async()决定是创建新线程还是回收旧线程。一个或简单地在当前线程上运行任务。它返回一个未来。

回答by Radoslav.B

"The class template std::packaged_task wraps any callable target (function, lambda expression, bind expression, or another function object) so that it can be invoked asynchronously. Its return value or exception thrown is stored in a shared state which can be accessed through std::future objects."

"The template function async runs the function f asynchronously (potentially in a separate thread) and returns a std::future that will eventually hold the result of that function call."

“类模板 std::packaged_task 包装了任何可调用目标(函数、lambda 表达式、绑定表达式或其他函数对象),以便可以异步调用它。它的返回值或抛出的异常存储在可以访问的共享状态中通过 std::future 对象。”

“模板函数 async 异步运行函数 f(可能在一个单独的线程中)并返回一个 std::future,它最终将保存该函数调用的结果。”