Vert.X CompositeFuture 用法
CompositeFuture 是一种特殊的 Future,它可以包装一个 Future 列表,从而让一组异步操作并行执行;然后协调这一组操作的结果,作为 CompositeFuture 的结果。本文将介绍 CompositeFuture 的用法以及几种协调方式,掌握这些内容有助于解决多个 Future 的整合问题。
1. 概念
开发人员从两个方面关注一个 Future:状态和结果。CompositeFuture 是 Future,同样要从这两个方面关注它。
CompositeFuture 的结果(消息)类型是 CompositeFuture 本身,也就是说 CompositeFuture#result()
返回值类型固定是 CompositeFuture。它可以用来表示一组结果,可以通过 list()
或 causes()
一次性读取一组结果或异常,也可以通过resultAt(index)
或cause(index)
读取单个结果或异常。
CompositeFuture cf = CompositeFuture.all(future1, future2);
cf.onSuccess(res -> {
CompositeFuture result = cf.result(); // 它的结果也是 CompositeFuture 类型
List<Double> results = result.list(); // 一次性读取一组结果
List<Throwable> cause = result.causes(); // 一次性读取一组异常
Double r1 = result.resultAt(0); // 读取第 0 个 Future 的结果
Throwbale t1 = result.cause(0); // 读取第 0 个 Future 的异常
});
CompositeFuture 的状态随着列表中 Future 状态的变化而变化。例如:当列表中所有 Future 都成功完成时,CompositeFuture 才是成功完成;或者,当列表中只要有一个 Future 成功完成时,CompositeFuture 就是成功完成。
CompositeFuture 作为 Future 协调器,提供了 all, any, join 三种协调方式。所谓协调,就是把一组 Future 包装成一个新的 Future,即 CompositeFuture,它的状态随着所包装列表中 Future 状态的变化而变化。
下面通过几种场景示例详细介绍这几种协调方式。
2. all
假如有一个金融系统,它有一个功能是统计某个客户的银行存款总额,需要向各个不同的银行系统发送余额查询请求,然后把这些请求的返回结果相加作为最终结果。一种高效的方式是并行发送请求,然后在所有请求都有结果时将结果汇总。使用 CompositeFuture 的 all 操作可以很方便地达到这个目的。
Future<Double> f1 = queryBalance("bank_a", "Robothy");
Future<Double> f2 = queryBalance("bank_b", "Robothy");
CompositeFuture future = CompositeFuture.all(f1, f2);
future.map(results -> { // results 是一个 CompositeFuture
Double balance1 = results.resultAt(0);
Double balance2 = results.resultAt(1);
return balance1 + balance2;
}).onSuccess(totalBalance -> System.out.println("Total balance is " + totalBalance))
.onFailure(Throwable::printStackTrace);
其中 queryBalance 的方法签名:
Future<Double> queryBalance(String bank, String username);
queryBalance 返回的是 Future,CompositeFuture#all()
把两个 Future 包装了起来,返回一个 CompositeFuture,当两个 Future 都成功完成时,这个 CompositeFuture 才算成功完成;随后转换操作 map 所设置的同步函数得以执行,通过 resultAt 方法读取结果,并将结果相加,作为总余额返回。此外,两个 queryBalance 并行执行。
上面这个例子只从 2 个银行获取余额,实际上,每个客户开会行的数量是不定的,一个客户通常对应着一个银行列表。对于这种情况,可以将多个 Future 放到一个 List 当中,再通过 CompositeFuture#all(List<Future> futures)
方法对一个 Future 列表进行包装。
List<String> banks = Arrays.asList("bank1", "bank2", "bank3", ...);
List<Future> futureList = banks.stream().map(bank -> queryBalance(bank, "Robothy"))
.collect(Collectors.toList());
CompositeFuture.all(futureList)
.map(results -> {
Double totalBalance = 0.0;
List<Double> balanceList = results.list();
for (Double balance : balanceList) {
totalBalance += balance;
}
return totalBalance;
})
.onSuccess(totalBalance -> System.out.println("Total balance is " + totalBalance))
.onFailure(Throwable::printStackTrace);
上面代码中,客户 "Robothy" 对应着一个银行列表,通过流操作把银行列表转化为 List<Future> futureList
。随后通过 CompositeFuture#all
对这个 Future 列表进行包装,当列表中的 Future 全部成功完成时,all 返回的 CompositeFuture 才算成功完成。在读取结果的时候,这里使用了 list()
方法一次性读取所有 Future 的结果。
CompositeFuture 不仅能够协调结果类型相同的多个 Future,还可以协调结果类型不同的 Future。例如:下面例子以并行的方式获取用户信息和账户信息。
Future<User> f1 = getUserByName("Robothy");
Future<Account> f2 = getAccountByName("Robothy");
CompositeFuture.all(f1, f2)
.onSuccess(results -> {
User user = resuts.resultAt(0);
Account account = results.resultAt(1);
})
.onFailure(Throwable::printStackTrace);
通过 CompositeFuture#all
包装得到 Future 列表都已成功完成时,all()
返回的 CompositeFuture 才算完成;当其中一个 Future 失败时,CompositeFuture 立即失败。
3. join
join 是另一种协调方式,当它包装的所有 Future 都已成功完成时,join()
返回的 CompositeFuture 才算成功完成。当其中一个 Future 失败,CompositeFuture 在等待所有 Future 都(成功或失败)完成之后失败。
下面这个例子的目的是找到网络延迟最小的服务器。
List<String> hosts = Arrays.asList("10.0.1.123", "10.0.1.124", "10.0.1.125", ...);
// 异步函数 ping 将 host 映射为 Future<Long>
List<Future> futures = hosts.stream().map(host -> ping(host)).collect(Collectors.toList());
CompositeFuture cf = CompositeFuture.join(futures);
cf.onComplete(res -> { // 这里是 onComplete,无论 cf 成功还是失败,都将执行。
CompositeFuture delays = res.result();
Long minDelay = Long.MAX_VALUE;
int minDelayIdx = -1;
for (int i=0; i<delays.size(); i++) {
Long delay = delays.resultAt(i);
if (null != delay) { // 第 i 个 Future 成功完成(如果失败, delay 为 null)
if (delay < minDelay) {
minDelay = delay;
minDelayIdx = i;
}
}
}
if (minDelayIdx != -1) {
System.out.println("Min delay: " + minDelay + ", server: " + hosts.get(minDelayIdx));
} else {
System.out.println("All servers are unreachable.");
}
})
.onFailure(Throwable::printStackTrace);
join 和 all 的区别在于:当包装的 Future 列表中有 1 个失败时,all()
得到的 CompositeFuture 立即失败,而join()
所包装的 CompositeFuture 会等待列表中的所有 Future 都完成时才失败。
此外,CompositeFuture 包装了多个 Future,意味着可能会有多个失败的 Future,而 Future#onFailure
只能够处理一个异常对象。这个异常对象是失败 Future 中,索引号最小的 Throwable 对象,并非最先失败的 Future 对应的 Throwable。例如下面这个例子总是输出 "f1 error"。
CompositeFuture.join(
Future.future(promise -> promise.fail(new RuntimeException("f1 error"))),
Future.future(promise -> promise.fail(new RuntimeException("f2 error")))
)
.onFailure(cause -> System.err.println(cause.getMessage())); // 总是输出 f1 error
}
要处理每个异常对象,需要在 onComplete 设置的处理器中进行操作。
CompositeFuture.join(f1, f2, ...)
.onComplete(res -> {
CompositeFuture results = res.result();
for (int i=0; i<results.size(); i++) {
Throwbale cause = results.cause(i);
if (null != cause) { // 第 i 个 Future 失败了
cause.printStackTrace();
}
}
});
4. any
all 和 join 都需要在列表中所有的 Future 都成功的情况下,CompositeFuture 才算成功,而 any 只要有一个 Future 成功了,CompositeFuture 就会立即成功完成;当所有 Future 都失败了,CompositeFuture 才是失败。
下面这个例子表示客户端向一个分布式系统的多个副本节点发送相同的消息,只要有一个节点返回成功,则表示消息发送成功。
String msg = "Hello";
List<String> hosts = Arrays.asList("10.0.0.1", "10.0.0.2", ...);
List<Future> futures = hosts.stream().map(host -> send(host, msg)).collect(Collectors.toList());
CompositeFuture.any(futures)
.onSuccess(results -> {
for (int i=0; i<results.size(); i++) {
if (null != results.resultAt(i)) {
System.out.println(hosts.get(i) + " received message.");
}
}
})
.onFailure(Throwable::printStackTrace);
5. 小结
CompositeFuture 作为 Future 的子接口,和普通 Future 一样可以处理消息和转化为另一个 Future 的能力。特殊的是,它的消息类型也是 CompositeFuture,它的状态随着所包装的若干 Future 状态的变化而变化。
CompositFuture 包装 Future 的方式或者说协调方式有三种:all, join, any。需要根据不同的应用场景来选择不同的包装方式。
- all: 所有的 Future 都成功完成时,才算成功完成;只要有一个 Future 失败,则立即失败;
- join: 所有的 Future 都成功完成时,才算成功完成;有 Future 失败时,等待所有的 Future 都完成才完成;
- any: 只要有一个 Future 成功完成,则立即成功完成;所有 Future 都失败时,才算失败
Vert.X CompositeFuture 用法的更多相关文章
- Vert.x Core 文档手册
Vert.x Core 文档手册 中英对照表 Client:客户端 Server:服务器 Primitive:基本(描述类型) Writing:编写(有些地方译为开发) Fluent:流式的 Reac ...
- matlab中patch函数的用法
http://blog.sina.com.cn/s/blog_707b64550100z1nz.html matlab中patch函数的用法——emily (2011-11-18 17:20:33) ...
- sass基本用法(转载)
SASS入门教程及用法指南 2014年8月27日 8489次浏览 作为前端开发人员,你肯定对css很熟悉,但是你知道css可以自定义吗?大家都知道,js中可以自定义变量,css仅仅是一个标记语言,不是 ...
- SASS用法指南-转
作者: 阮一峰 日期: 2012年6月19日 原文地址:http://www.ruanyifeng.com/blog/2012/06/sass.html 艹,没想到sass 2012年就有了.现在 ...
- CSS预处理器之SASS用法指南
CSS预处理器之SASS用法指南 一.什么是SASS Sass是是一种基于ruby编写的CSS预处理器,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. 诞生于200 ...
- sass基本用法
什么是SASS SASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. 本文总结了SASS的主要用法.我的目标是,有了这篇文章,日常 ...
- scss初学小结(转阮一峰老师SASS用法指南http://www.ruanyifeng.com/blog/2012/06/sass.html)
1.安装 SASS是Ruby语言写的,但是两者的语法没有关系.不懂Ruby,照样使用.只是必须先安装Ruby,然后再安装SASS. 假定你已经安装好了Ruby,接着在命令行输入下面的命令: gem i ...
- [转]SASS用法指南
[转]SASS用法指南 转自阮一峰 SASS用法指南 一.什么是SASS SASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. 本文总结了 ...
- Scss基础用法
Scss基础用法 一.注释用法: (1)//comment:该注释只是在.scss源文件中有,编译后的css文件中没有. (2)/! /:重要注释,任何style的css文件中都会有,一般放置css文 ...
随机推荐
- 【Java】这 35 个 Java 代码优化细节!
前言 代码 优化 ,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没 ...
- JS Promise对象学习
Promise对象的三个状态 pending(进行中) fulfilled(已成功) rejected(已失败) Promise代表一个异步操作,对象的状态一旦改变,就不会再改变 Promise构造函 ...
- Grep 命令有什么用? 如何忽略大小写? 如何查找不含 该串的行?
是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印 出来. grep [stringSTRING] filename grep [^string] filename
- BMZCTF simple_pop
simple_pop 打开题目得到源码 这边是php伪协议的考点,需要去读取useless.php 解码获得源码 <?php class Modifier { protected $var; p ...
- ros工作空间中文件夹结构
ROS 编译系统 catkin 详解 ros系统学习之Catkin编译系统 ROS--catkin编译系统.package.xml和CMakeList.txt文件 1.build:编译空间 存放CMa ...
- d面试题汇总
HTML Doctype作用,HTML5 为什么只需要写<!DOCTYPE HTML>? html5有哪些新特性?移除了哪些元素? 简述一下你对HTML语义化的理解? 行内元素有哪些,块级 ...
- Wepy-小程序踩坑记
引言 用过原生开发的小程序也知道除了api 其他功能性的内容并不多对于需要做大型项目来说是比较难入手的,因此朋友推荐的wepy我就入坑鸟...这么一个跟vue的开发方式类似的框架,不过说起来跟vue类 ...
- WebGL小姐姐教我学画画之起手式
初次接触WebGL,如有错误之处欢迎留言,共同学习进步. v WebGL的自画像 我,WebGL,全名Web Graphics Library,是为了让死宅程序猿们(摊手)能在浏览器上为所欲为的画女朋 ...
- Android Studio 异常以及解决方案
1. Error:(1, 0) Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVER ...
- vue 相关问题整理