我为什么要使用std :: async?

时间:2013-07-31 06:30:20

标签: c++ c++11 asynchronous future stdasync

我正在尝试深入探索新C ++ 11标准的所有选项,同时使用std :: async并阅读其定义,我注意到两件事,至少在linux下使用gcc 4.8.1:< / p>

  • 它被称为 async ,但它有一个真正的“顺序行为”,基本上在你调用与你的异步函数相关的 future 的行中 foo < / em>,程序阻塞,直到 foo 的执行完成。
  • 它取决于与其他外部库完全相同的外部库,以及更好的非阻塞解决方案,这意味着pthread,如果您想使用std::async,则需要使用pthread。

在这一点上我很自然地问为什么选择std :: async甚至是一组简单的仿函数?这是一个根本无法扩展的解决方案,您调用的未来越多,您的程序响应就越少。

我错过了什么吗?你能展示一个被授予以异步,非阻塞方式执行的例子吗?

5 个答案:

答案 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::asyncstd::launch::deferred启动。如果你没有指定它,允许实现选择,并且它可以选择使用延迟评估,这将导致在你尝试从未来获得结果时完成所有工作,从而导致更长的块。因此,如果要确保工作是异步完成的,请使用std::launch::async

答案 2 :(得分:13)

我认为您的问题是std::future说它会阻止get。如果结果尚未准备好,它只会阻止

如果您可以安排结果已经准备好,这不是问题。

有很多方法可以知道结果已经准备好了。您可以轮询future并询问它(相对简单),您可以使用锁或原子数据来传达它已准备好的事实,您可以构建一个框架来传递“已完成”future个项目在消费者可以与之交互的队列中,您可以使用某种信号(这只是一次阻止多个事物或轮询)。

或者,您可以完成本地可以完成的所有工作,然后阻止远程工作。

作为一个例子,想象一下并行递归合并排序。它将数组拆分为两个块,然后在一个块上进行async排序,同时对另一个块进行排序。一旦对其一半进行排序,原始线程就无法继续进行,直到第二个任务完成。所以它做.get()并阻止。一旦两个部分都已经排序,它就可以进行合并(理论上,合并也可以至少部分地并行完成)。

此任务的行为类似于在外部与之交互的线性任务 - 完成后,数组将被排序。

然后我们可以将它包装在std::async任务中,并且有一个future排序数组。如果我们想要,我们可以添加一个信号程序让我们知道future已经完成,但只有当我们有一个等待信号的线程时才有意义。

答案 3 :(得分:3)

referencehttp://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/

有三种类型的政策,

  1. launch::async
  2. launch::deferred
  3. launch::async|launch::deferred

默认情况下,launch::async|launch::deferred被传递到std::async