Professional Documents
Culture Documents
1 - Coroutines 基本概念与极简模型
1 - Coroutines 基本概念与极简模型
官方Coroutines 资料
Coroutines 参考
https://en.cppreference.com/w/cpp/language/coroutines
Coroutines 标准
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4775.pdf
Coroutines 支持库
https://github.com/lewissbaker/cppcoro
• task<T>
• shared_task<T>
• generator<T>
• async_generator<T>
• async_mutex<T>
Coroutines Hello world
https://blog.panicsoftware.com/your-first-coroutine/
Coroutines 是什么
使用者角度
1. 同步方式
2. 异步方式1
3. 异步方式2
4. boost::future
5. coroutines
6. 代码实例
抽象概念
• 一种编译器支持的对 set_jump(...) long_jump(...)的安全封装, 实现线程栈间安全跳转
• 堆上的栈
• 对boost::coroutines boost::coroutines2 boost::CO2 的标准化和取舍
• goroutiens 的 c++版
• 可挂起函数
• 建模: 2个动态过程(如线程)的交互合同订立基础标准
从C语言角度看C++ coroutines
三个重点
• second stack frame
• __builtin_coro_resume
• __builtin_coro_suspend
LLVM coroutins
https://llvm.org/docs/Coroutines.html
• C++
• Rust
• Webassembly
与普通函数的区别
coroutines 普通函数 备注
栈在 堆上 线程栈上
哪里
参数 C++ C++ 大部分coroutines 参
数要传值
1 std::future<> foo(bar_t 1 std::future<> foo(bar_t
2 { st& a)
3 co_return; 2 {
4 } 3 return;
4 }
分类
stackless stackfull (假想代码) / Generic 备注
Coroutines
Lambd stackful
a coroutines 在lua
等脚本语言中支
持
C++ C++ 假想代码在
c++20 中非法
将来可能会实
1 auto fStackless = [](au
a)
1 auto fStackfull = [](auto
a)
现??
2 -> generator<int> 2 {
3 { 3 co_yield a * a;
4 co_yield a * a; 4 }
5 } 5
6 6 std::future<> foo()
7 std::future<> foo() 7 {
8 { 8 auto yieldIt = fStackl
9 fStackless(1); ss(1);
10 co_return; 9 yieldIt();
11 } 10
11 generator<int> r = fSt
ckless(2);
12 co_return;
13 }
• stackless
• stackfull
Coroutines 为什么
解耦与建模:
◦ 编译器级将动态过程封装为对象, 并提供和外界交互的基础规则
◦ 很大程度上提高了函数式编程的适用性,现在函数可完成动态模型转换
◦ coroutines模式创建(库撰写)与库使用者分离良好
◦ 提供了一种可能: 将并发同步问题限制在库(模式)的开发中, 减少库(模式)使用者对并发同步的需
求
性能:
◦ 充分利用编译器对local scope的优化能力
◦ 标准建议编译器尽可能减少堆上栈的使用
◦ 大量减少对线程的需要
◦ 大量减少线程上下文切换的需要
高并发:
◦ 编译器级(LLVM built-in) 上下文切换;
◦ 大幅度减少锁的使用;
◦ 为尽可能用atomic替代锁提供基础
易用性:
◦ coroutines的使用者逻辑符合常规同步思维
◦ 减少传递不必要的参数或者减少全局变量
◦ 已经足够成熟 Microsoft 2019年推出 WindowsRT库大量使用, 取代MFC, C++/CRT
◦ 异步数据可分段 co_yield (future 不能)
Coroutines How
Coroutines 编译器及库支持
Coroutines 代码生成及调试
gdb/lldb 最新版暂时还不支持 读取coroutins 栈中的变量
常规线程栈
极简模型
C++ C++
1 // 前台代码, 库的使用者写 1 // 后台库代码2
2 T foo() 2 class P
3 { 3 {
4 //...... 4 waitable_t yield_value(auto&&)
5 w_t w; 5 {
6 float a = co_await w; 6 //......
7 //...... 7 }
8 co_yield 20.5; 8 void return_value(auto&&)
9 //...... 9 {
10 co_return 100; 10 //......
11 } 11 }
12 12 };
13
C++
1 // 后台库代码3
2 // 侵入式
3 struct T
4 {
5 using promise_type = P;
6 };
7
8 // 非侵入式 需 partial specify
std::coroutine_traits
9 template<>
10 struct std::coroutine_traits<T>
11 {
12 using promise_type = P;
13 };
C++
1 // 后台库代码1
2 // waitable_t
3 struct w_t
4 {
5 bool await_ready()
6 {
7 return false;
8 }
9
10 void await_suspend(auto
coro)
11 {
12
13
__builtin_coro_resume(coro)
;
14 }
15
16 float await_resume()
17 {
18 return 0.9;
19 }
20 };
21
与ECMAScript6概念对比
js 异步 C++协程 备注
await co_await 关键字
yield co_yield 关键字
Promise cppcoro::task<> 库
Generator cppcoro::generaor<> 库
AsyncGenerator cppcoro::async_generaor<> 库
Promise.all() cppcoro::when_all(...) 库
Promise.any() when_any(...) 自己写的
Promise.prototype.then() f_then(...) 自己写的
Promise.resolve() f_make_ready_task(...) 自己写的
Promise.reject() f_make_exceptional_task(...) 自己写的
Promise.race() f_xxx() 研究中
JavaScript C++ 自己写的
相同点
• 等待语义
• yield语义
• 解决callback陷阱
• when_all(...)
• when_any(...)
• 都是stackless的
不同点
透明度 线程 模式 同步等待 易用性 Performan
ce
C++协程 完全透明 多线程 高度可定制 cppcoro::sync_ 中 高
背后是sjlj 有时仍需要mutex等 cppcoro 里用 wait(...) std::ta 很多并发同
同步操作 coroutine甚至实 sk<> 步可用
现了协作式 pendin atomic模
mutex, latch, g 型完成
fence 及锁
js 异步 不透明 没有线程概念 ECMAScript标准 无 高 高
V8实现可能使用了并 规定 取决于v8
发?? • Promise 实现
• Generator
• AnsycGenerat
or
• AsyncIterable