前言

通常来说,有两种异步模式,一种是基于goroutine的用户态协程并发模型,另一种是基于Future/Promise的并发模型。后者能够将多个Future串联,改善回调地狱这一情况。其实Javascript早就提供了Promise模型,异步基于事件循环来做,每次都是将异步事件插入时间序列等待下一次调用。而像C++/Rust这些语言就必须通过额外的executor库就安排异步事件的执行。Rust中已经有了非常优秀的异步运行时tokioFolly的实现应当是差不多的。

Folly的介绍基于自底向上进行的方法,从底层building block到上层高级原语。

Core

core是沟通PromiseFuture的桥梁,属于二者的共享状态。

KeepAlive and Deferred

KeepAlive是对executor的安全引用,保证不会在KeepAlive存活时析构executor

Deferred是尚未设置实际executor的代理,后续需要注入指定的executor

Info flow

Core维护三种info flow

  • producer => consumer:resultcallbackexecutorpriority
  • consumer => producer:interruptinterrupt 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分为CoreBaseCore<T>,将与模板有关的信息集中在Core<T>中。

生命周期管理

由于设计了代理机制,this可以代理其他core对象,因此,使用attached_反映引用计数。

另外使用callbackRef_反映lambda的引用计数。

为什么显式的使用引用计数而不是智能指针呢?

doCallBack设计

对于某些特殊情况,doCallBack可以inline执行callback函数(也就是在setResult时直接执行callBack函数)。

Barrier

这是一个常见的CountDownLatchWaitGroup(前者更合适)的同步原语,返回的所有Promise会在最后一个wait调用后被"resolve"。值得一提的是,内部实现用一个atomic_64维护两个atomic_32状态,分别记录当前正在调用wait的数量和所有已经调用的数量。当前者 == 0 && 后者 == size 时,进行变量析构、内存释放。

同时,处于性能优化的考虑,结构体设计采用了变长数组 + 定位new。

struct ControlBlockAndPromise {
    ControlBlock cb;
    BoolPromise promises[1];
};

Promise

FuturePromise的一个典型应用如下

///   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

七月流火
1 声望1 粉丝