C++ 20 协程(一)

C++ 20 协程(一)

介绍

C++ 20提供的是非对称的、一等对象、无栈的协程(Coroutines in C++20 are asymmetric, first-class, and stackless)

所谓协程,即用户级线程,一种用于将异步代码同步化的编程机制,使得程序的执行流可以在多个并行事务之间切换但又不必承担切换带来的过高的性能损耗。当前很多的编程语言都内置协程特性或者有自己的协程库,如C/C++的libco、golang的goroutine等。而在实现机制上,又可以划分为有栈协程和无栈协程

协程是可以在保持状态的同时暂停和恢复执行的函数

C++ 20 协程(一)_第1张图片

非对称协程与对称协程

非对称协程(asymmetric coroutines)是跟一个特定的调用者绑定的,协程让出CPU时,只能让回给原调用者。那到底是什么东西“不对称”呢?第一,非对称在于程序控制流转移到被调协程时使用的是suspend/resume操作,而当被调协程让出 CPU 时使用的却是return/yield操作。第二,协程间的地位也不对等,caller与callee关系是确定的,不可更改的,非对称协程只能返回最初调用它的协程。微信团队的libco其实就是一种非对称协程,Boost C++库也提供了非对称协程。另外,挂起(suspend)和恢复(resume)跟yield的区别是:yield后的协程,之后还会被切换回来,但是被suspend挂起的协程,除非调用resume()恢复它,否则永远不会再被执行到。在不同语言中,这三者会有不同的叫法,比如call也会调用新函数时也会同时实现suspend旧函数的功能,有的语言用yield/resume和return,不一而论,但区别不变。

对称协程(symmetric coroutines)则不同,被调协程启动之后就跟之前运行的协程没有任何关系了。协程的切换操作,一般而言只有一个操作yield或return,用于将程序控制流转移给另外的协程。对称协程机制一般需要一个调度器的支持,按一定调度算法去选择yield或return的目标协程。Go语言提供的协程,其实就是典型的对称协程。不但对称,goroutines还可以在多个线程上迁移。这种协程跟操作系统中的线程非常相似,甚至可以叫做“用户级线程”。

一等对象(第一类对象)

[python - What are “first-class” objects? - Stack Overflow](https://stackoverflow.com/questions/245192/what-are-first-class-objects

第一类对象(英语:First-class object)在计算机科学中指可以在执行期创造并作为参数传递给其他函数或存入一个变量的实体[1]。将一个实体变为第一类对象的过程叫做“物件化”(Reification)[2]。

无栈协程

有栈(stackful)协程通常的实现手段是在堆上提前分配一块较大的内存空间(比如 64K),也就是协程所谓的“栈”,参数、return address 等都可以存放在这个“栈”空间上。如果需要协程切换,那么通过 swapcontext 一类的形式来让系统认为这个堆上空间就是普通的栈,这就实现了上下文的切换。

有栈协程最大的优势就是侵入性小,使用起来非常简便,已有的业务代码几乎不需要做什么修改,但是 C++20 最终还是选择了使用无栈协程,主要出于下面这几个方面的考虑。

无栈协程是一个可以暂停和恢复的函数,是函数调用的泛化。

我们知道一个函数的函数体(function body)是顺序执行的,执行完之后将结果返回给调用者,我们没办法挂起它并稍后恢复它,只能等待它结束。而无栈协程则允许我们把函数挂起,然后在任意需要的时刻去恢复并执行函数体,相比普通函数,协程的函数体可以挂起并在任意时刻恢复执行。

C++ 20 协程(一)_第2张图片

所以,从这个角度来说,无栈协程是普通函数的泛化。

总结一下,有栈协程是用户态线程,无栈协程就是函数调用

你可能感兴趣的:(C++,c++20,c++,开发语言)