目录
Vert.x 源码阅读 (1) - Future 和 Promise
这是 Vert.x 项目源码阅读笔记的第一篇, 主要讲一下最基础的 Future
和 Promise
的概念。Future
和 Promise
实际上是异步编程中非常基础的两个抽象,大部分程序员想必都非常熟悉,我这里主要是整理为主。
Vert.x 中的 Future
和 Promise
AsyncResult
接口
Vert.x 中的 Future
扩展了 AsyncResult
。AsyncResult
有点像一个 Monad
,它包装了一个结果,或者是一个错误。注意 AsyncResult
这个接口并不包含结果还没有准备就绪的状态,这个状态是由 Future
暴露出来的。
Future
接口
Future
逻辑上表达了一个异步计算的结果。它扩展了 AsyncResult
接口,主要提供了两类方法:
- 判断是否已经完成:
isComplete
。 - 注册回调方法,例如
onComplete
。
等待结果的一方直接面对的,应该是一个 Future
对象。这个对象对于结果使用方来说,是只读的。使用方可以不断的 poll
它直到计算完成,结果 ready。同时使用也可用基于这个 Future
创建一个新的 Future
对象。
Promise
接口
Promise
有点难解释,我觉得我们可以把它理解成 Future
的可写的另一端。实际完成异步计算的结果提供方,在干完活之后,将结果写入这个 Promise
。Promise
会负责通知自己对应的 Future
结果已经准备就绪了。
Golang 中的 Channel
我感觉 Golang 中的 channel
是一个有点相似的概念。Future
和 Promise
是 channel
的两端。这也意味着,我们可以用 Future
和 Promise
来做线程间同步,虽然我们不应该怎么做,而应该根据你的情况使用更加适合的,专门用于同步的抽象。
一般的使用场景
在一般情况下,Promise
和 Future
的使用往往符合这样的模式。我们假设存在 A 和 B 两个实体,A 需要 B 执行一个任务,然后将结果告诉自己。为了达到这个目的,一般会经过一下几个步骤:
- A 触发整个流程,往往是通过调用 B 提供的某个接口,这个接口一般都返回一个
Future
对象。 - B 的接口中创建了一对
Promise
和Future
。Future
会被返回给 A。 - A 获得返回的
Future
之后一般会在这个Future
上注册回调函数,表示收到结果之后要做什么。 - B 在结果计算出来之后调用
Promise::complete
方法,而这个complete
方法会调用 A 在Future
上注册的函数。
样例
为了加深理解,这里给出几段代码,用来品品这两个抽象的使用方式。为了方便理解,这里去掉了和 context
相关的代码。
Future
的 map
方法
1 | public Future<O> map(Function<I, O> transformer) { |
通过 map
的代码,我们可以清楚地发现,Promise
和 Future
非常类似于一个 channel
。我们总是留住一根管子的一端,把另一端交给下游。自己干完活就对着管子吼一声。
CompositeFuture
的实现
这里为了方便理解做了一点简化,实际上 CompositeFuture
是一个接口,真正的实现在 CompositeFutureImpl
中。
1 | public class CompositeFuture implements Future<CompositeFuture> { |
CompositFuture
的实现思路也很简单,就是在每一个子 Future
上注册一个回调来通知自己一个子 Future
已经完成。如果所有的子 Future
都完成了,就可以把自己标记成完成。