nij*_*sen 120 c++ multithreading packaged-task c++11 stdasync
在使用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';
Run Code Online (Sandbox Code Playgroud)
和
auto f = std::async(std::launch::async,
[](int a, int b) { return a + b; }, 2, 3);
std::cout << f.get() << '\n';
Run Code Online (Sandbox Code Playgroud)
似乎做了完全相同的事情.据我所知,有可能是一个重大的区别,如果我跑std::async带std::launch::deferred,但有一个在这种情况下?
这两种方法有什么区别,更重要的是,我应该使用哪种用例?
Zet*_*eta 149
实际上,如果您使用相当长的函数,例如,您刚刚给出的示例显示了差异
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
std::async另一方面,std::asyncwith 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";
Run Code Online (Sandbox Code Playgroud)
但在尝试使用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;
*/
Run Code Online (Sandbox Code Playgroud)
因此,如果您想要真正的异步,则需要保留返回的future,或者如果情况发生变化则不关心结果:
{
auto pizza = std::async(get_pizza);
/* ... */
if(need_to_go)
return; // ~future will block
else
eat(pizza.get());
}
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅香草萨特的文章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";
Run Code Online (Sandbox Code Playgroud)
此外,packaged_task需要在调用之前调用f.get(),否则程序将冻结,因为将来永远不会准备好:
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);
Run Code Online (Sandbox Code Playgroud)
使用std::async,如果你想一些事情做,他们就完成了的时候真的不关心,而且std::packaged_task如果你想包裹起来的东西,以便将它们移动到其他线程或以后打电话给他们.或者,引用克里斯蒂安:
最后,a
std::packaged_task只是一个较低级别的实现功能std::async(这就是为什么它可以比std::async与其他更低级别的东西一起使用更多的东西,比如std::thread).简单地说astd::packaged_task是std::function链接到astd::future和std::asyncwrap并调用std::packaged_task(可能在不同的线程中).
Dan*_*ica 10
std::packaged_task允许我们获得std::future某个callable的“边界” ,然后控制该 callable 的执行时间和地点,而无需该 future 对象。
std::async启用第一个,但不启用第二个。也就是说,它允许我们获得某些可调用对象的未来,但是如果没有该未来对象,我们就无法控制它的执行。
这是一个可以用 解决std::packaged_task但不能用解决的问题的实际示例std::async。
考虑您想要实现一个线程池。它由固定数量的工作线程和共享队列组成。但是什么是共享队列呢?std::packaged_task这里非常适合。
template <typename T>
class ThreadPool {
public:
using task_type = std::packaged_task<T()>;
std::future<T> enqueue(task_type task) {
// could be passed by reference as well...
// ...or implemented with perfect forwarding
std::future<T> res = task.get_future();
{ std::lock_guard<std::mutex> lock(mutex_);
tasks_.push(std::move(task));
}
cv_.notify_one();
return res;
}
void worker() {
while (true) { // supposed to be run forever for simplicity
task_type task;
{ std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this]{ return !this->tasks_.empty(); });
task = std::move(tasks_.top());
tasks_.pop();
}
task();
}
}
... // constructors, destructor,...
private:
std::vector<std::thread> workers_;
std::queue<task_type> tasks_;
std::mutex mutex_;
std::condition_variable cv_;
};
Run Code Online (Sandbox Code Playgroud)
此类功能无法通过std::async. 我们需要返回一个std::futurefrom enqueue()。如果我们std::async在那里调用(即使使用延迟策略)并返回std::future,那么我们将无法选择如何执行 中的可调用对象worker()。请注意,您不能为同一共享状态创建多个 future(future 是不可复制的)。
| 归档时间: |
|
| 查看次数: |
24773 次 |
| 最近记录: |