C++ 协程 - 何时、如何使用?

K.R*_*ark 11 c++ coroutine c++20 c++-coroutine

作为一名对协程概念非常陌生的 C++ 程序员新手,我正在尝试研究和利用该功能。虽然这里有协程的解释:What is a coroutine?

我还不确定何时以及如何使用协程。提供了几个示例用例,但这些用例具有可以通过 C++20 之前的功能实现的替代解决方案:(例如:无限序列的惰性计算可以通过具有私有内部状态变量的类来完成)。

因此,我正在寻找协程特别有用的任何用例。

协程概念

(来自Izana发布的图片)

Nic*_*las 15

在这种情况下,“协程”这个词有点重载。

您所指的问题中描述了称为“协程”的一般编程概念。C++20 添加了一种称为“协程”的语言功能。虽然 C++20 的协程与编程概念有些相似,但它们并不那么相似

在底层,这两个概念都建立在函数(或函数调用堆栈)停止执行并将执行控制权转移给其他人的能力之上。这样做的目的是期望控制权最终会交还给暂时放弃执行的函数。

C++ 协程与一般概念的不同之处在于它们的局限性和设计的应用程序。

co_await <expr>作为一种语言结构,它会执行以下操作(非常广泛)。它询问表达式<expr>当前是否有要提供的结果值。如果确实有结果,则表达式会提取该值,并且当前函数中的执行将照常继续。

如果当前无法解析表达式(可能是因为<expr>正在等待外部资源或异步进程或其他原因),则当前函数将挂起其执行并将控制权返回给调用它的函数。协程还将自身附加到<expr>对象,以便一旦<expr>获得该值,它就应该使用该值恢复协程的执行。此恢复可能会也可能不会在当前线程上发生。

这样我们就看到了C++20协程的模式。co_await当前线程的控制返回给调用者,但协程的恢复由正在编辑的值的性质决定。调用者获取一个对象,该对象代表协程将产生但尚未产生的未来值。调用者可以等待它准备好或去做其他事情。它还可以自行计算 co_await未来的值,创建一个协程链,在计算出一个值后即可恢复。

我们还看到了主要限制:暂停仅适用于立即函数。除非每个函数调用单独执行自己的操作,否则您无法挂起整个函数调用堆栈co_await

C++ 协程是三方之间的复杂舞蹈:等待的表达式、执行等待的代码以及协程的调用者。使用co_yield本质上删除了这三方之一。即,预计不会涉及生成的表达式。它只是一个将转储给调用者的值。所以yield协程只涉及协程函数和调用者。Yielding C++ 协程更接近“协程”的概念。

使用生成协程向调用者提供多个值通常称为“生成器”。这使您的代码有多“简单”取决于您的生成器框架(即:协程返回类型及其关联的协程机制)。但是好的生成器框架可以向生成公开范围接口,允许您将 C++20 范围应用于它们并进行各种有趣的组合。