为什么我应该使用std::async
Why should I use std::async?
我试图深入探索新C++11标准的所有选项,在使用std::async并阅读其定义时,我注意到了两件事,至少在带有gcc 4.8.1:的linux下是这样
- 它被称为async,但它有一个真正的"顺序行为",基本上在你调用与异步函数foo相关的future的那一行,程序会阻塞,直到foo执行完成
- 它依赖于与其他库完全相同的外部库,以及更好的非阻塞解决方案,即
pthread
,如果您想使用std::async
,则需要pthread
在这一点上,我很自然地会问,为什么选择std::async而不是一组简单的函数?这是一个根本不可扩展的解决方案,你调用的未来越多,你的程序响应就越差。
我是不是错过了什么?你能展示一个被允许以异步、非阻塞的方式执行的例子吗?
- 它被称为async,但它有一个真正的"顺序行为"
不,如果使用std::launch::async
策略,那么它将在新线程中异步运行。如果不指定策略,则可能会在新线程中运行。
基本上,在调用与异步函数foo相关联的future的行中,程序会阻塞,直到执行完foo为止。
它只在foo还没有完成的情况下阻止,但如果它是异步运行的(例如,因为您使用了std::launch::async
策略),它可能在您需要它之前就已经完成了
- 它依赖于与其他库完全相同的外部库,以及更好的非阻塞解决方案,这意味着pthread,如果你想使用std::async,你需要pthread
错了,它不必使用Pthreads来实现(在Windows上也不是,它使用了ConcRT功能。)
在这一点上,我很自然地会问,为什么选择std::async而不是一组简单的函数?
因为它保证了线程安全并在线程之间传播异常。你能用一组简单的函子做到这一点吗?
这是一个根本不可扩展的解决方案,你调用的未来越多,你的程序响应就越差。
不一定。如果您没有指定启动策略,那么智能实现可以决定是启动新线程,还是返回延迟函数,或者返回稍后决定何时可以使用更多资源的内容。
现在,对于GCC的实现,如果您不提供启动策略,那么对于当前版本,它将永远不会在新线程中运行(有一个bugzilla报告),但这是该实现的属性,而不是std::async
的属性。您不应该将标准中的规范与特定的实现混淆。阅读一个标准库的实现是学习C++11的一种糟糕的方式。
你能展示一个被允许以异步、非阻塞的方式执行的例子吗?
这不应该阻止:
auto fut = std::async(std::launch::async, doSomethingThatTakesTenSeconds);
auto result1 = doSomethingThatTakesTwentySeconds();
auto result2 = fut.get();
通过指定启动策略,您可以强制异步执行,如果您在执行过程中做其他工作,则结果将在需要时准备好。
如果您需要异步操作的结果,则无论您使用什么库,都有要阻止。这个想法是,你可以选择何时阻止,希望当你这样做的时候,你阻止的时间可以忽略不计,因为所有的工作都已经完成了。
还要注意,std::async
可以通过策略std::launch::async
或std::launch::deferred
来启动。如果您不指定它,则允许实现进行选择,并且它很可能选择使用延迟评估,这将导致在您试图从未来获得结果时完成所有工作,从而导致更长的块。因此,如果您想确保工作是异步完成的,请使用std::launch::async
。
我认为您的问题是std::future
说它阻塞了get
。只有当结果还没有准备好时,它才会阻止。
如果你能安排结果已经准备好,这不是问题。
有很多方法可以知道结果已经准备好了。你可以轮询future
并询问它(相对简单),你可以使用锁或原子数据来传递它已经准备好的事实,你可以建立一个框架来将"完成的"future
项目交付到消费者可以交互的队列中,你可以用某种信号(这只是一次阻塞多个项目,或者轮询)。
或者,你可以在本地完成所有可以做的工作,然后阻止远程工作。
举个例子,想象一个并行递归合并排序。它将数组拆分为两个块,然后在一个块上执行async
排序,同时对另一个块进行排序。一旦完成了对其一半的排序,起始线程就无法继续,直到第二个任务完成。所以它做了一个.get()
和块。一旦对两半都进行了排序,它就可以进行合并(理论上,合并也可以至少部分并行进行)。
对于那些在外部与它交互的人来说,这个任务的行为就像一个线性任务——当它完成时,数组就会被排序。
然后,我们可以将其封装在std::async
任务中,并获得一个future
排序的数组。如果我们愿意,我们可以添加一个信号过程,让我们知道future
已经完成,但只有当我们有一个线程在等待信号时,这才有意义。
在参考中:http://en.cppreference.com/w/cpp/thread/async
如果设置了async标志(即policy&std::launch::async!=0),则async在单独的执行线程上执行函数f,就好像由std::thread(f,args…)派生,除了如果函数f返回值或引发异常,该值存储在共享通过std::future可访问的状态,async返回到调用者。
记录抛出的异常是一个不错的属性。
http://www.cplusplus.com/reference/future/async/
有三种类型的策略,
launch::async
launch::deferred
launch::async|launch::deferred
则默认情况下CCD_ 22被传递给CCD_。
- 为什么std::async使用同一个线程运行函数
- 为什么可以将左值传递给"std::async",即使它引用了右值
- 使用 std::async 时死锁,将来作为成员
- 为什么我不能将引用作为 std::async 的函数参数传递
- std::async from std::async in windows xp
- std::async 如何工作:为什么它会调用这么多次复制/移动?
- std::async 不会立即调用
- std::async 如果线程是从 DLL 创建的,则会阻止进程退出?
- 使用 std::vector<std::future<int>> 和 std::async 启动几个线程时中止
- 在Visual Studio中,与std::async一起使用时不调用"thread_local"变量"析构函数,这是一个错误吗?
- 可能的 std::async 实现错误 Windows
- C++从 std::async 函数读取命名空间中的全局变量标志
- std::async 究竟是如何执行的?
- 使用 g++8 和 c++20 的 std::async 编译问题
- 如何有效地使用 std::async 对指针数组执行操作
- 标准C++11是否保证std::async(std::launch::asyncfunc)在单独的线程中启动func
- 何时需要使用std::async(std::launch::asyncfunc())而不是func(()
- std::async([](){ std::cout<< "Hello " ; }) build error
- GCC 的行为与 std::async(std::launch::async) 与 Clang 的行为
- std::async - std::launch::async | std::launch::deferred