为什么我应该使用std :: async?
我试图深入探索新的C ++ 11标准的所有选项,同时使用std :: async并阅读其定义,我注意到了两件事情,至少在linux下使用gcc 4.8.1:
pthread
,如果要使用std::async
,则需要pthread。 在这一点上,我很自然地问为什么选择std :: async而不是一组简单的函子呢? 这个解决方案甚至根本无法扩展规模,您呼叫的未来越多,程序响应也就越少。
我错过了什么吗? 你能否展示一个被授予以异步,非阻塞方式执行的示例?
如果您需要异步操作的结果,那么无论您使用哪个库,都必须阻止。 这个想法是,你可以选择什么时候阻止,并且希望当你这样做的时候,你阻止了一个微不足道的时间,因为所有的工作已经完成了。
还要注意std::async
可以用政策推出std::launch::async
或std::launch::deferred
。 如果您没有指定它,则可以选择实现,并且可以选择使用延迟评估,这会在您尝试从未来获得结果时导致所有工作都已完成,从而导致较长的块。 所以如果你想确保工作是异步完成的,可以使用std::launch::async
。
不,如果你使用std::launch::async
策略,它会在一个新线程中异步运行。 如果您未指定可能在新线程中运行的策略。
基本上在你调用将与异步函数foo关联的将来的行中,程序将阻塞,直到foo执行完成。
它只会在foo没有完成时阻塞,但如果它是异步运行的(例如,因为您使用std::launch::async
策略),它可能在您需要之前完成。
错误的是,它不必使用Pthreads来实现(在Windows上它不是,它使用ConcRT功能)。
在这一点上,我很自然地问为什么选择std :: async而不是一组简单的函子呢?
因为它保证了线程安全并跨线程传播异常。 你能用一套简单的仿函数来做到吗?
这个解决方案甚至根本无法扩展规模,您呼叫的未来越多,程序响应也就越少。
不必要。 如果您没有指定启动策略,那么智能实现可以决定是否启动新线程,或返回延迟函数,或返回稍后决定的事情,以便有更多资源可用时。
现在的确,在GCC的实现中,如果你没有提供启动策略,那么对于当前版本,它将永远不会运行在一个新线程中(这里有一个bugzilla报告),但这是该实现的属性,而不是std::async
一般的std::async
。 您不应该将标准中的规范与特定的实现混淆。 阅读一个标准库的实现是学习C ++ 11的一个不好的方法。
你能否展示一个被授予以异步,非阻塞方式执行的示例?
这不应该阻止:
auto fut = std::async(std::launch::async, doSomethingThatTakesTenSeconds);
auto result1 = doSomethingThatTakesTwentySeconds();
auto result2 = fut.get();
通过指定启动策略,您可以强制执行异步执行,并且如果您在执行其他任务时执行了其他任务,那么当您需要时,结果将会准备就绪。
我认为你的问题是std::future
说它会阻止get
。 只有在结果尚未准备好的情况下,它才会阻止。
如果您可以安排结果已经准备就绪,这不是问题。
有很多方法可以知道结果已经准备好。 您可以轮询future
并询问它(相对简单),您可以使用锁定或原子数据来传达它已准备好的事实,您可以构建一个框架以将“已完成”的future
项目交付到消费者可以与之交互的队列中,你可以使用某种类型的信号(它只是一次阻止多个事物,或轮询)。
或者,您可以完成您可以在本地完成的所有工作,然后阻止远程工作。
作为一个例子,设想一个并行递归合并排序。 它将数组拆分为两个块,然后对一个块进行async
排序,同时对另一个块进行排序。 一旦完成对其一半的排序,直到第二个任务完成后,始发线程才能进行。 所以它做了一个.get()
和块。 一旦完成了两部分的排序,就可以进行合并(理论上,合并至少可以部分并行完成)。
这个任务对于那些在外部进行交互的人来说就像是一个线性任务 - 完成后,数组将被排序。
然后我们可以将它包装在一个std::async
任务中,并且有future
排序数组。 如果我们想要的话,我们可以添加一个信号程序让我们知道future
已经完成,但只有当我们有一个线程等待信号时才有意义。
上一篇: Why should I use std::async?
下一篇: Are the days of passing const std::string & as a parameter over?