乐趣区

关于c++:Folly库代码赏析5FuturePromise模型

前言

通常来说,有两种异步模式,一种是基于 goroutine 的用户态协程并发模型,另一种是基于 Future/Promise 的并发模型。后者可能将多个 Future 串联,改善回调天堂这一状况。其实 Javascript 早就提供了 Promise 模型,异步基于事件循环来做,每次都是将异步事件插入工夫序列期待下一次调用。而像 C++/Rust 这些语言就必须通过额定的 executor 库就安顿异步事件的执行。Rust中曾经有了十分优良的异步运行时 tokioFolly 的实现该当是差不多的。

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

Core

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

退出移动版