Pav*_*aka 84 c++ coroutine c++20
什么是c ++ 20中的协同程序?
它与"Parallelism2"或/和"Concurrency2"的不同之处(见下图)?
以下图片来自ISOCPP.
Yak*_*ont 155
在一个抽象的层面上,Coroutines将执行状态与创建执行线程的想法分开了.
SIMD(单指令多数据)具有多个"执行线程",但只有一个执行状态(它只适用于多个数据).可以说并行算法有点像这样,因为你有一个"程序"在不同的数据上运行.
线程有多个"执行线程"和多个执行状态.您有多个程序和多个执行线程.
Coroutines具有多个执行状态,但不拥有执行线程.你有一个程序,程序有状态,但它没有执行的线程.
协同程序最简单的例子是来自其他语言的生成器或枚举.
在伪代码中:
function Generator() {
for (i = 0 to 100)
produce i
}
Run Code Online (Sandbox Code Playgroud)
将Generator被调用,并在第一时间调用时返回0.记住它的状态(协同程序的执行情况会有多少状态),下次你调用它时会继续它停止的状态.所以它下次返回1.然后2.
最后它到达循环的末尾并从函数的末尾掉落; 协程已经完成.(这里发生的事情因我们所讨论的语言而异;在python中,它会引发异常).
协同程序为C++带来了这种能力.
协同程序有两种; 堆叠和无堆叠.
无堆栈协程仅在其状态及其执行位置存储局部变量.
堆栈协程存储整个堆栈(如线程).
无拼接协程可以非常轻量级.我读到的最后一个提议基本上将你的功能改写成有点像lambda的东西; 所有局部变量都进入对象的状态,标签用于跳转到/从协同程序"产生"中间结果的位置.
生成一个值的过程称为"yield",因为协同程序有点像协作多线程; 你正在将执行点交还给调用者.
Boost实现了堆栈协程; 它可以让你调用一个函数来为你屈服.堆叠的协同程序更强大,但也更昂贵.
协同程序比简单的发电机更多.您可以在协程中等待协程,它允许您以有用的方式组成协同程序.
协同程序,如if,循环和函数调用,是另一种"结构化goto",它允许您以更自然的方式表达某些有用的模式(如状态机).
在C++中Coroutines的具体实现有点有趣.
在最基本的层面上,它为C++添加了一些关键字:co_return co_await co_yield以及一些与它们一起使用的库类型.
函数通过在其体内具有其中一个来成为协程.因此,根据他们的声明,他们与功能无法区分.
当在函数体中使用这三个关键字中的一个时,会发生一些标准强制检查返回类型和参数,并将函数转换为协程.此检查告诉编译器在函数挂起时存储函数状态的位置.
最简单的协程是一个发电机:
generator<int> get_integers( int start=0, int step=1 ) {
for (int current=start; true; current+= step)
co_yield current;
}
Run Code Online (Sandbox Code Playgroud)
co_yield暂停函数执行,将状态存储在中generator<int>,然后current通过返回值generator<int>.
您可以循环返回的整数.
co_await同时让你将一个协程拼接到另一个协同上.如果你在一个协程中并且在进行之前你需要一个等待的东西(通常是一个协程)的结果,你co_await就可以了.如果他们准备好了,你马上行动; 如果没有,你暂停直到你等待的等待准备就绪.
std::future<std::expected<std::string>> load_data( std::string resource )
{
auto handle = co_await open_resouce(resource);
while( auto line = co_await read_line(handle)) {
if (std::optional<std::string> r = parse_data_from_line( line ))
co_return *r;
}
co_return std::unexpected( resource_lacks_data(resource) );
}
Run Code Online (Sandbox Code Playgroud)
load_data是一个协程,它std::future在命令资源打开时生成一个,我们设法解析到我们找到所请求数据的点.
open_resource和read_lines可能是异步协同程序,它们打开文件并从中读取行.该co_await连接的悬挂和准备状态load_data,以他们的进步.
C++协同程序比这更灵活,因为它们是在用户空间类型之上实现的最小语言功能集.用户空间类型有效地定义了什么co_return co_await和co_yield 意思 - 我见过人们使用它来实现monadic可选表达式,这样co_await一个空的可选项自动将空状态传播到外部可选:
modified_optional<int> add( modified_optional<int> a, modified_optional<int> b ) {
return (co_await a) + (co_await b);
}
Run Code Online (Sandbox Code Playgroud)
代替
std::optional<int> add( std::optional<int> a, std::optional<int> b ) {
if (!a) return std::nullopt;
if (!b) return std::nullopt;
return *a + *b;
}
Run Code Online (Sandbox Code Playgroud)
Lot*_*har 13
协程就像一个C函数,它有多个return语句,当被调用时,第二次不会在函数开始时执行,而是在上一次执行返回之后的第一条指令处开始执行.此执行位置与所有自动变量一起保存,这些变量将存在于非协同功能的堆栈中.
Microsoft之前的一个实验性协程实现确实使用了复制堆栈,因此您甚至可以从深层嵌套函数返回.但这个版本被C++委员会拒绝了.例如,您可以使用Boosts光纤库来实现此实现.