Coroutines(协程)¶
title: gcc支持情况?
gcc 10 支持协程,需要添加选项 -fcoroutines打开,默认不启用。
title: C++20 协程特点?
协程是**无栈的**,它们通过返回到调用方暂停执行,并且恢复执行所需的数据与栈分离存储。这样就可以编写异步执行的顺序代码(例如不使用显式的回调来处理非阻塞 I/O),还支持作用于惰性计算的无限序列上的算法及其他用途。
1 什么是协程?¶
协程是一个函数,它是能暂停(suspend)执行以在之后恢复(resume)的函数。
2 协程与进程、线程的比较¶
- 协程既不是进程,也不是线程,协程仅仅是一个特殊的函数,协程跟他们就不是一个维度。
- 一个进程可以包含多个线程,一个线程可以包含多个协程。
- 一个线程内的多个协程虽然可以切换,但是这多个协程是串行执行的,只能在这一个线程内运行,没法利用CPU多核能力。
- 协程与进程一样,它们的切换都存在上下文切换问题。(协程的切换是在用户态的,不会陷入内核)
3 协程的使用场景¶
协程**不适合计算密集型**的场景,因为*单个线程内的协程是串行的,并不能利用多核能力*。
- I/O 阻塞型场景(包括网络传输、文件读写),当 I/O 阻塞时切换到另一个协程上执行。I/O 密集型需要多线程+协程模式。
4 libco IO 工作流程¶
- libco 工作流程
- 将阻塞操作改变为非阻塞,sql 命令往数据库发送,其实就是往一个 fd 上写数据。
- 数据发出去后非阻塞操作马上返回。然后将这个 fd 挂在 epoll 上(当发出去的命令返回或者超时,epoll_wait 会返回通知的)。
- 保存当前(协程)程序运行时的上下文,这样就相当于 yield 切走了当前(协程)程序 A。
- 然后加载其它等待执行的(协程)程序 B 的上下文,返回上一次 B 执行源码的下一条源码地址去运行,这样 A 在等待 sql 结果返回的过程中,被唤醒的 B 仍然能继续工作,B 如果遇到阻塞 IO 也同样执行上述步骤。
- sql 命令返回结果,epoll_wait 收到通知返回,resume 唤醒 fd 对应的 A(协程)程序。
5 C++20 协程编写¶
5.1 个关键字¶
如果函数的定义进行了下列操作之一,那么它是协程:
- 用
co_await
运算符暂停执行,直到恢复:
task<> tcp_echo_server() {
char data[1024];
while (true) {
std::size_t n = co_await socket.async_read_some(buffer(data));
co_await async_write(socket, buffer(data, n));
}
}
- 用关键词
co_yield
暂停执行并返回一个值:
generator<int> iota(int n = 0) {
while(true)
co_yield n++;
}
- 用关键词
co_return
完成执行并返回一个值:
lazy<int> f() {
co_return 7;
}