C++ 为什么要使用std::async?

C++ 为什么要使用std::async?,c++,c++11,asynchronous,future,stdasync,C++,C++11,Asynchronous,Future,Stdasync,我试图深入探讨新C++11标准的所有选项,在使用std::async并阅读其定义时,我注意到两件事,至少在使用GCC4.8.1的linux下是这样的: 它被称为异步,但它有一个真正的“顺序行为”,基本上是在调用与异步函数foo相关联的未来的那一行,程序阻塞直到foo的执行完成 它依赖于与其他库完全相同的外部库,以及更好的非阻塞解决方案,这意味着pthread,如果要使用std::async,则需要pthread 在这一点上,我自然会问为什么选择std::async而不是一组简单的函子?这是一

我试图深入探讨新C++11标准的所有选项,在使用std::async并阅读其定义时,我注意到两件事,至少在使用GCC4.8.1的linux下是这样的:

  • 它被称为异步,但它有一个真正的“顺序行为”,基本上是在调用与异步函数foo相关联的未来的那一行,程序阻塞直到foo的执行完成
  • 它依赖于与其他库完全相同的外部库,以及更好的非阻塞解决方案,这意味着
    pthread
    ,如果要使用
    std::async
    ,则需要pthread
在这一点上,我自然会问为什么选择std::async而不是一组简单的函子?这是一个根本不可扩展的解决方案,您呼叫的未来越多,您的程序响应性就越差


我错过什么了吗?您能展示一个被授权以异步、非阻塞方式执行的示例吗?

如果您需要异步操作的结果,那么无论您使用什么库,您都必须阻塞。这个想法是,你可以选择什么时候阻塞,希望当你这样做的时候,你阻塞的时间可以忽略不计,因为所有的工作都已经完成了

还请注意,
std::async
可以使用策略
std::launch::async
std::launch::deferred
启动。如果您不指定它,则允许实现进行选择,并且它可以选择使用延迟评估,这将导致在您尝试从将来获得结果时完成所有工作,从而导致更长的块。因此,如果您想确保工作是异步完成的,请在以下目录中使用
std::launch::async

如果设置了异步标志(即policy&std::launch::async!=0),则 async在单独的执行线程上执行函数f,就像 由std::thread(f,args…)生成,除非函数f 返回值或引发异常,该值存储在共享 可通过异步返回到的std::future访问的状态 来电者


保留抛出异常的记录是一个很好的属性。

我认为您的问题在于
std::future
说它阻塞了
get
。只有当结果尚未准备好时,它才会阻塞

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

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

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

例如,想象一个并行递归合并排序。它将数组拆分为两个块,然后对一个块执行
异步
排序,同时对另一个块进行排序。一旦完成对其一半的排序,原始线程将无法进行,直到第二个任务完成。因此它执行
.get()
和块。一旦对两半进行了排序,它就可以进行合并(理论上,合并至少可以部分并行进行)

对于那些在外部与它交互的人来说,这个任务的行为就像一个线性任务——当它完成时,数组被排序

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

  • 它被称为异步,但它有一个真正的“顺序行为”
否,如果使用
std::launch::async
策略,则它将在新线程中异步运行。如果不指定策略,则它可能在新线程中运行

基本上,在调用与异步函数foo相关联的future的行中,程序阻塞,直到foo的执行完成

只有当foo尚未完成时,它才会阻塞,但如果它是异步运行的(例如,因为您使用
std::launch::async
策略),它可能在您需要它之前已经完成

  • 它依赖于与其他库完全相同的外部库,以及更好的非阻塞解决方案,这意味着pthread,如果要使用std::async,则需要pthread

错误的是,它不必使用Pthreads实现(在Windows上它不是,它使用ConcRT特性)

在这一点上,我自然会问为什么选择std::async而不是一组简单的函子

因为它保证了线程安全,并在线程之间传播异常。你能用一组简单的functor来做到这一点吗

这是一个根本不可扩展的解决方案,您呼叫的未来越多,您的程序响应性就越差

不一定。如果您没有指定启动策略,那么智能实现可以决定是启动新线程,还是返回延迟函数,或者返回稍后决定何时有更多资源可用的内容

现在,在GCC的实现中,如果您不提供启动策略,那么在当前版本中,它将永远不会在新线程中运行(这是有原因的)但这是该实现的一个属性,而不是通常的
std::async
。您不应该将标准中的规范与特定实现混淆。阅读一个标准库的实现是了解C++11的一个糟糕的方法

您能否展示一个被授权以异步、非阻塞方式执行的示例

这不应阻碍:

auto fut = std::async(std::launch::async, doSomethingThatTakesTenSeconds);
auto result1 = doSomethingThatTakesTwentySeconds();
auto result2 = fut.get();
通过指定启动