我正在尝试深入探索新C ++ 11标准的所有选项,同时使用std :: async并阅读其定义,我注意到两件事,至少在linux下使用gcc 4.8.1:< / p>
pthread
,如果您想使用std::async
,则需要使用pthread。在这一点上我很自然地问为什么选择std :: async甚至是一组简单的仿函数?这是一个根本无法扩展的解决方案,您调用的未来越多,您的程序响应就越少。
我错过了什么吗?你能展示一个被授予以异步,非阻塞方式执行的例子吗?
答案 0 :(得分:74)
- 它被称为异步,但它有一个真正的“顺序行为”,
不,如果您使用std::launch::async
策略,则它会在新线程中异步运行。如果您未指定策略,则可能在新线程中运行。
基本上在你调用与异步函数foo相关的未来的行中,程序会阻塞,直到foo的执行完成为止。
它仅在foo未完成时阻止,但如果它是异步运行的(例如,因为您使用std::launch::async
策略),它可能在您需要之前完成。
- 它取决于与其他人完全相同的外部库,以及更好的非阻塞解决方案,这意味着pthread,如果你想使用std :: async,你需要pthread。
错误,它不必使用Pthreads实现(在Windows上它不是,它使用ConcRT功能。)
在这一点上我很自然地问为什么选择std :: async甚至是一组简单的仿函数?
因为它保证线程安全并跨线程传播异常。你能用一套简单的仿函数做到吗?
这是一个根本无法扩展的解决方案,您调用的未来越多,您的程序响应就越少。
不一定。如果您没有指定启动策略,那么智能实现可以决定是启动新线程,还是返回延迟函数,或者在更多资源可用时返回稍后决定的内容。
现在,对于GCC的实现,如果你不提供启动策略然后使用当前版本,它将永远不会在新线程中运行(对此有一个bugzilla report)但是这是一个属性实施,而不是std::async
。您不应该将标准中的规范与特定实现混淆。阅读一个标准库的实现是学习C ++ 11的一种不好的方法。
你能展示一个被授予以异步,非阻塞方式执行的例子吗?
这不应该阻止:
auto fut = std::async(std::launch::async, doSomethingThatTakesTenSeconds);
auto result1 = doSomethingThatTakesTwentySeconds();
auto result2 = fut.get();
通过指定启动策略,您强制执行异步,如果您在执行时执行其他工作,则结果将在您需要时准备好。
答案 1 :(得分:53)
如果您需要异步操作的结果,那么无论您使用哪个库,都要来阻止。这个想法是你可以选择何时阻止,并且希望当你这样做时,你可以阻止一段时间,因为所有的工作都已经完成了。
另请注意,std::async
可以使用政策std::launch::async
或std::launch::deferred
启动。如果你没有指定它,允许实现选择,并且它可以选择使用延迟评估,这将导致在你尝试从未来获得结果时完成所有工作,从而导致更长的块。因此,如果要确保工作是异步完成的,请使用std::launch::async
。
答案 2 :(得分:13)
我认为您的问题是std::future
说它会阻止get
。如果结果尚未准备好,它只会阻止 。
如果您可以安排结果已经准备好,这不是问题。
有很多方法可以知道结果已经准备好了。您可以轮询future
并询问它(相对简单),您可以使用锁或原子数据来传达它已准备好的事实,您可以构建一个框架来传递“已完成”future
个项目在消费者可以与之交互的队列中,您可以使用某种信号(这只是一次阻止多个事物或轮询)。
或者,您可以完成本地可以完成的所有工作,然后阻止远程工作。
作为一个例子,想象一下并行递归合并排序。它将数组拆分为两个块,然后在一个块上进行async
排序,同时对另一个块进行排序。一旦对其一半进行排序,原始线程就无法继续进行,直到第二个任务完成。所以它做.get()
并阻止。一旦两个部分都已经排序,它就可以进行合并(理论上,合并也可以至少部分地并行完成)。
此任务的行为类似于在外部与之交互的线性任务 - 完成后,数组将被排序。
然后我们可以将它包装在std::async
任务中,并且有一个future
排序数组。如果我们想要,我们可以添加一个信号程序让我们知道future
已经完成,但只有当我们有一个等待信号的线程时才有意义。
答案 3 :(得分:3)
在reference:http://en.cppreference.com/w/cpp/thread/async
中如果设置了异步标志(即policy&amp; std :: launch :: async!= 0),那么 async在单独的执行线程上执行函数f,就好像 由std :: thread(f,args ...)生成,除了函数f的 返回一个值或抛出异常,它存储在共享中 状态可以通过std :: future访问异步返回到 呼叫者强>
保留异常记录是一个很好的属性。
答案 4 :(得分:0)
http://www.cplusplus.com/reference/future/async/
有三种类型的政策,
launch::async
launch::deferred
launch::async|launch::deferred
默认情况下,launch::async|launch::deferred
被传递到std::async
。