前言
通常来说,有两种异步模式,一种是基于goroutine
的用户态协程并发模型,另一种是基于Future/Promise
的并发模型。后者能够将多个Future
串联,改善回调地狱这一情况。其实Javascript
早就提供了Promise
模型,异步基于事件循环来做,每次都是将异步事件插入时间序列等待下一次调用。而像C++/Rust
这些语言就必须通过额外的executor
库就安排异步事件的执行。Rust
中已经有了非常优秀的异步运行时tokio
,Folly
的实现应当是差不多的。
对Folly
的介绍基于自底向上进行的方法,从底层building block
到上层高级原语。
Core
core
是沟通Promise
和Future
的桥梁,属于二者的共享状态。
KeepAlive and Deferred
KeepAlive
是对executor
的安全引用,保证不会在KeepAlive
存活时析构executor
。
Deferred
是尚未设置实际executor
的代理,后续需要注入指定的executor
。
Info flow
Core
维护三种info flow
- producer => consumer:
result
、callback
、executor
、priority
- consumer => producer:
interrupt
、interrupt handler
类似于Linux中的信号,用于取消或xxcallback
的执行 - lifetime control: 2 ref counts(
attached_
和callbackref_
),控制析构
下面是一张 producer => consumer
的状态转换图,清晰地转换Core
的各种状态以及触发条件。
/// +----------------------------------------------------------------+
/// | ---> OnlyResult ----- |
/// | / \ |
/// | (setResult()) (setCallback()) |
/// | / \ |
/// | Start ---------> ------> Done |
/// | \ \ / |
/// | \ (setCallback()) (setResult()) |
/// | \ \ / |
/// | \ ---> OnlyCallback --- |
/// | \ or OnlyCallbackAllowInline |
/// | \ \ |
/// | (setProxy()) (setProxy()) |
/// | \ \ |
/// | \ ------> Empty |
/// | \ / |
/// | \ (setCallback()) |
/// | \ / |
/// | --------> Proxy ---------- |
/// +----------------------------------------------------------------+
模块设计
Core
分为CoreBase
和Core<T>
,将与模板有关的信息集中在Core<T>
中。
生命周期管理
由于设计了代理机制,this可以代理其他core
对象,因此,使用attached_
反映引用计数。
另外使用callbackRef_
反映lambda
的引用计数。
为什么显式的使用引用计数而不是智能指针呢?
doCallBack设计
对于某些特殊情况,doCallBack
可以inline
执行callback
函数(也就是在setResult
时直接执行callBack
函数)。
Barrier
这是一个常见的CountDownLatch
或WaitGroup
(前者更合适)的同步原语,返回的所有Promise
会在最后一个wait
调用后被"resolve"
。值得一提的是,内部实现用一个atomic_64
维护两个atomic_32
状态,分别记录当前正在调用wait
的数量和所有已经调用的数量。当前者 == 0 && 后者 == size 时,进行变量析构、内存释放。
同时,处于性能优化的考虑,结构体设计采用了变长数组 + 定位new。
struct ControlBlockAndPromise {
ControlBlock cb;
BoolPromise promises[1];
};
Promise
Future
和Promise
的一个典型应用如下
/// auto [p, f] = makePromiseContract(executor);
/// g = std::move(f).then([](MyValue&& x) {
/// ...executor runs this code if/when a MyValue is ready...
/// });
/// ...launch the async producer that eventually calls p.setResult()...
Future
SemiFuture vs Future
SemiFuture
没有指定executor
,通过.via
指定executor
变身为future
。
Future
更有趣一点
then
仅仅是设置了callback
getVia
阻塞获取结果,重复调用e->drive
直到fulfilled
via
设置了executor
生成了future
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。