6

Seastar 之 future/promise 原理(1)

 2 years ago
source link: https://forrestsu.github.io/posts/architecture/archi-seastar/seastar-future-promise/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Seastar 之 future/promise 原理(1)

2020年3月26日
| 字数 1978

The future is the value, the promise is the function that sets the value – essentially the return value (future) of an asynchronous function (promise). Setting the value of a future is also called resolving, fulfilling, or binding it. —— from Wikipedia

1 Preface

Seastar (f-p-c) 属于Reactive编程的一个子集。
Seastar的性能源自 sharded,cooperative,non-blocking的微任务调度设计, 而 f-p-c 是将 task 送入调度程序的一种更友好的方式。

Seastar 引入了 future/promise, 把面向 callback 编程变成了面向future/promise编程, 将以前的回调代码包装在 lambda_task 中,然后交给future调度。

  • future 是一个 value ;
  • promise 是一个函数,本质是返回 value 的异步函数;
  • promise 写入 value 的过程又称为解决、履行或绑定它

具体来说,当区分用法时,future 是变量的只读占位符视图,而 promise 是可写的单一赋值设置未来 value 的容器。

为了满足复杂的异步编程需要,Seastar重新实现了一些有别于标准库中的数据结构,因为像 thread safe这样的要求是无需考虑的。这里主要讨论的是Seastar实现的 future/promise。

(注: 下文将使用 f/p 作为 future/promise的简称)

2 future & promise

future 和 promise 都有一个 _state 指针成员,都指向同一个future_state<T>堆对象;
future_state 堆对象作为一个桥梁,为 future 和 promise 建立了联系;
同时 future_state 可以携带一个task。如下图所示:

3 f/p 类图

详细的类图如下,需要注意一点, promise有一个get_future() 方法,
是调用 future 的 private 构造函数构造的。

4 f/p 调用时序图

下面来看看 Seastar f/p 调用的时序图:

Continuation在这里可以理解为:一个 task 的单链表,一个task内链着一个task;

f/p是成对使用的,相同颜色的f/p表示一对,因为他们操作同一个future_state;
future.then() 可以看成一个中间人,他会定义一个新的 promiseA,并产生 futureA, 把 this,promiseA 转移到一个 lambda_task 内,最后返回futureA。

5 对象占用的空间

我们可以看到 future/promise 对象一般都位于栈上,都只有1个指针成员,所以大小 8 bytes;
而且这两个对象在定义之后,是需要被 move 到不同的lambda_task之中的,可谓是非常高效的设计。

但是future_state对象位于堆上,而且占用的字节会比较多。

6 future & promise 改进

后面为了减少堆空间占用,作者不再使用 future_state 作为桥梁,而使 f/p 直接建立相互关系, 并且 future_state 只用于存储 task 和 task 的执行结果 tuple。

7 对象生命周期

一般来说, promise 对象在产生后,会被move到一个 lambda_task 里面,
lambda_task 执行完使命也就完成了,析构lambda_task时,promise 对象生命周期随之结束。
而 future 对象此时还在一个待执行的 task 里面。

(1) promise 对象会构造一个future对象,同时 future_state 的所有权也会转交给future对象;
(2) promise 会先于 future 对象消亡,满足严格的偏序关系。
(3) future.then() 会将传入的lambda + 当前的future自身 + 局部定义的promise, 这3个对象的所有权都转移到一个更大的 lambda_W 之中, 最后将这个还未ready的 lambda_W 放入 future_state 的task成员上,然后等待时机被调度。

最后问个问题:future_state之为啥要用future前缀命名?
因为future_state 对象的生命周期由future对象管理。

Reference

《全文完》

文末尾给出了《Seastar 源码之美》系列文章的目录,希望你能在这个列表里找到自己感兴趣的内容。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK