c++ - 为什么 std::future 从 std::packaged_task 和 std::async 返回不同?
问题描述
我知道了future
返回 from的原因std::async
有一些特殊的共享状态,通过这种共享状态wait on returned future
发生在未来的析构函数中。但是当我们使用 时std::pakaged_task
,它的未来不会表现出相同的行为。要完成打包任务,您必须显式调用get()
来自 的future
对象packaged_task
。
现在我的问题是:
std::async
未来(thinking vs )的内部实现可能是什么std::packaged_task
?- 为什么相同的行为不适用于
future
返回 fromstd::packaged_task
?或者,换句话说,如何停止相同的行为std::packaged_task
future
?
要查看上下文,请参阅以下代码:
它不等待完成countdown
任务。但是,如果我取消评论// int value = ret.get();
,它将完成countdown
并且很明显,因为我们实际上是在阻止返回的未来。
// packaged_task example
#include <iostream> // std::cout
#include <future> // std::packaged_task, std::future
#include <chrono> // std::chrono::seconds
#include <thread> // std::thread, std::this_thread::sleep_for
// count down taking a second for each value:
int countdown (int from, int to) {
for (int i=from; i!=to; --i) {
std::cout << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Lift off!" <<std::endl;
return from-to;
}
int main ()
{
std::cout << "Start " << std::endl;
std::packaged_task<int(int,int)> tsk (countdown); // set up packaged_task
std::future<int> ret = tsk.get_future(); // get future
std::thread th (std::move(tsk),10,0); // spawn thread to count down from 10 to 0
// int value = ret.get(); // wait for the task to finish and get result
std::cout << "The countdown lasted for " << std::endl;//<< value << " seconds.\n";
th.detach();
return 0;
}
如果我使用在另一个线程上std::async
执行任务countdown
,无论我是否在get()
返回的future
对象上使用,它都会完成任务。
// packaged_task example
#include <iostream> // std::cout
#include <future> // std::packaged_task, std::future
#include <chrono> // std::chrono::seconds
#include <thread> // std::thread, std::this_thread::sleep_for
// count down taking a second for each value:
int countdown (int from, int to) {
for (int i=from; i!=to; --i) {
std::cout << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Lift off!" <<std::endl;
return from-to;
}
int main ()
{
std::cout << "Start " << std::endl;
std::packaged_task<int(int,int)> tsk (countdown); // set up packaged_task
std::future<int> ret = tsk.get_future(); // get future
auto fut = std::async(std::move(tsk), 10, 0);
// int value = fut.get(); // wait for the task to finish and get result
std::cout << "The countdown lasted for " << std::endl;//<< value << " seconds.\n";
return 0;
}
解决方案
std::async
对如何以及在何处执行给定的任务有明确的了解。这就是它的工作:执行任务。要做到这一点,它必须把它放在某个地方。那个地方可能是一个线程池,一个新创建的线程,或者在一个由谁破坏future
.
因为async
知道函数将如何执行,所以它拥有 100% 的信息来构建一种机制,该机制可以在潜在的异步执行结束时进行通信,并确保如果你破坏future
了执行该函数最终将绕过实际执行它。毕竟,它知道那个机制是什么。
但packaged_task
没有。所做的只是存储一个packaged_task
可以使用给定参数调用的可调用对象,使用promise
函数返回值的类型创建 a,并提供一种获取 afuture
和执行生成该值的函数的方法。
任务实际执行的时间和地点无关紧要packaged_task
。future
如果没有这些知识,就无法构建使 's 析构函数与任务同步所需的同步。
假设您想在新创建的线程上执行任务。好的,因此要将其执行与future
' 销毁同步,您需要一个互斥锁,析构函数将阻塞该互斥锁,直到任务线程完成。
future
但是,如果您想在与析构函数的调用者相同的线程中执行任务怎么办?好吧,那么您不能使用互斥锁来同步它,因为它们都在同一个线程上。相反,您需要让析构函数调用该任务。这是一个完全不同的机制,它取决于你计划如何执行。
因为packaged_task
不知道您打算如何执行它,所以它无法执行任何操作。
请注意,这不是packaged_task
. 从用户创建的对象创建的所有 s都不会具有s的特殊属性。future
promise
async
future
所以问题真的应该是为什么这样async
工作,而不是为什么其他人不这样做。
如果您想知道这一点,那是因为两个相互竞争的需求:async
需要是一种高级的、脑死亡的简单方法来获得异步执行(破坏时同步是有意义的),并且没有人想创建一个新的future
除了析构函数的行为外,它与现有的类型相同。所以他们决定重载如何future
工作,使其实现和使用复杂化。
推荐阅读
- python - 网页抓取缺失值
- html - 如何修复无法向下滚动的网页?
- python - Numpy将函数应用于数组中的每个项目
- python - 在 django 中将多个模型组合在一个创建视图中
- php - jQuery Post 变量到 PHP
- c# - 无法在 Unity 中制作不平滑的移动脚本
- php - 通过 id 搜索时,Laravel 雄辩的关系将无法正常工作
- python - AttributeError: 'int' 对象在使用 Matplotlib 和 Tkinter 时没有属性 '_process_projection_requirements'
- google-cloud-platform - 输入音频是否必须在谷歌存储上?
- python - Python:新对象丢失数组属性