上次我们熟悉了ListenableFuture 。 我答应介绍更高级的技术,即转换和链接。 让我们从简单的事情开始。 假设我们有从某些异步服务获得的ListenableFuture<String> 。 我们还有一个简单的方法:

Document parse(String xml) {//...

我们不需要String ,我们需要Document 。 一种方法是简单地解析Future等待它)并在String上进行处理。 但是,更优雅的解决方案是在结果可用后立即应用转换,并将我们的方法视为始终返回ListenableFuture<Document> 。 这很简单:

final ListenableFuture<String> future = //...final ListenableFuture<Document> documentFuture = Futures.transform(future, new Function<String, Document>() {@Overridepublic Document apply(String contents) {return parse(contents);}
});

或更可读:

final Function<String, Document> parseFun = new Function<String, Document>() {@Overridepublic Document apply(String contents) {return parse(contents);}
};final ListenableFuture<String> future = //...final ListenableFuture<Document> documentFuture = Futures.transform(future, parseFun);

Java语法有一定的局限性,但请专注于我们刚刚做的事情。 Futures.transform()不会等待基础的ListenableFuture<String>应用parse()转换。 相反,它在后台注册了一个回调,希望在给定将来完成时得到通知。 在适当的时候对我们动态透明地应用了此转换。 我们仍然有Future ,但是这次包装了Document

因此,让我们更进一步。 我们还有一个异步的,可能长时间运行的方法,用于计算给定Document 相关性 (无论在这种情况下是什么):

ListenableFuturecalculateRelevance(Document pageContents) {//...

我们可以以某种方式将其与我们已经拥有的ListenableFuture<Document>吗? 第一次尝试:

final Function<Document, ListenableFuture<Double>> relevanceFun = new Function<Document, ListenableFuture<Double>>() {@Overridepublic ListenableFuture<Double> apply(Document input) {return calculateRelevance(input);}
};final ListenableFuture<String> future = //...
final ListenableFuture<Document> documentFuture = Futures.transform(future, parseFun);
final ListenableFuture<ListenableFuture<Double>> relevanceFuture = Futures.transform(documentFuture, relevanceFun);

哎哟! Double Future的未来,看起来不太好。 一旦我们解决了外部的未来,我们也需要等待内部的未来。 绝对不优雅。 我们可以做得更好吗?

final AsyncFunction<Document, Double> relevanceAsyncFun = new AsyncFunction<Document, Double>() {@Overridepublic ListenableFuture<Double> apply(Document pageContents) throws Exception {return calculateRelevance(pageContents);}
};final ListenableFuture<String> future = //comes from ListeningExecutorService
final ListenableFuture<Document> documentFuture = Futures.transform(future, parseFun);
final ListenableFuture<Double> relevanceFuture = Futures.transform(documentFuture, relevanceAsyncFun);

请非常仔细地查看所有类型和结果。 注意FunctionAsyncFunction之间的区别。 最初,我们有一个异步方法返回String future。 后来,我们对其进行了转换,以将String无缝转换为XML Document 。 内部将来完成后,此转换将异步发生。 具有Document future,我们想调用一个需要Document并返回Double future的方法。

如果调用relevanceFuture.get() ,则我们的Future对象将首先等待内部任务完成,其结果( String -> Document )将等待外部任务并返回Double 。 我们还可以在relevanceFuture上注册回调,该回调将在外部任务( calculateRelevance() )完成时触发。 如果您仍然在这里,那就是更加疯狂的转变。

请记住,所有这些都是循环发生的。 对于每个网站,我们都有ListenableFuture<String> ,我们将其异步转换为ListenableFuture<Double> 。 所以最后我们使用List<ListenableFuture<Double>> 。 这也意味着,为了提取所有结果,我们要么为每个ListenableFuture注册侦听器,要么等待它们中的每个。 根本没有进步。 但是,如果我们可以轻松地从List<ListenableFuture<Double>>ListenableFuture<List<Double>>怎么办? 仔细阅读-从期货清单到清单的未来。 换句话说,不是拥有一堆小小的期货,而是有一个将在所有子期货都完成后完成的期货–并且将结果一对一映射到目标列表。 猜猜,Guava可以做到这一点!

final List<ListenableFuture<Double>> relevanceFutures = //...;
final ListenableFuture<List<Double>> futureOfRelevance = Futures.allAsList(relevanceFutures);

当然,这里也没有等待。 包装器ListenableFuture<List<Double>>将在其期货之一完成时得到通知。 最后一个孩子ListenableFuture<Double>完成时,外部将来也完成。 一切都是事件驱动的,对您完全隐藏。

你认为就是这样吗? 假设我们要计算整个集合中最大的相关性。 您可能现在已经知道,我们不会等待List<Double> 。 相反,我们将注册从List<Double>Double

final ListenableFuture<Double> maxRelevanceFuture = Futures.transform(futureOfRelevance, new Function<List<Double>, Double>() {@Overridepublic Double apply(List<Double> relevanceList) {return Collections.max(relevanceList);}
});

最后,我们可以侦听maxRelevanceFuture完成事件,并使用JMS发送结果(异步!)。 如果您迷路了,这是完整的代码:

private Document parse(String xml) {return //...
}private final Function<String, Document> parseFun = new Function<String, Document>() {@Overridepublic Document apply(String contents) {return parse(contents);}
};private ListenableFuture<Double> calculateRelevance(Document pageContents) {return //...
}final AsyncFunction<Document, Double> relevanceAsyncFun = new AsyncFunction<Document, Double>() {@Overridepublic ListenableFuture<Double> apply(Document pageContents) throws Exception {return calculateRelevance(pageContents);}
};//...final ListeningExecutorService pool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)
);final List<ListenableFuture<Double>> relevanceFutures = new ArrayList<>(topSites.size());
for (final URL siteUrl : topSites) {final ListenableFuture<String> future = pool.submit(new Callable<String>() {@Overridepublic String call() throws Exception {return IOUtils.toString(siteUrl, StandardCharsets.UTF_8);}});final ListenableFuture<Document> documentFuture = Futures.transform(future, parseFun);final ListenableFuture<Double> relevanceFuture = Futures.transform(documentFuture, relevanceAsyncFun);relevanceFutures.add(relevanceFuture);
}final ListenableFuture<List<Double>> futureOfRelevance = Futures.allAsList(relevanceFutures);
final ListenableFuture<Double> maxRelevanceFuture = Futures.transform(futureOfRelevance, new Function<List<Double>, Double>() {@Overridepublic Double apply(List<Double> relevanceList) {return Collections.max(relevanceList);}
});Futures.addCallback(maxRelevanceFuture, new FutureCallback<Double>() {@Overridepublic void onSuccess(Double result) {log.debug("Result: {}", result);}@Overridepublic void onFailure(Throwable t) {log.error("Error :-(", t);}
});

它值得吗? 是的没有是的 ,因为我们了解了一些与期货/承诺一起使用的非常重要的构造和原语:链接,映射(转换)和归约。 该解决方案在CPU利用率方面非常出色-无需等待,阻塞等。请记住, Node.js的最大优势在于其“无阻塞”策略。 在Netty期货中也无处不在。 最后但并非最不重要的一点是,它感觉非常实用

另一方面,主要是由于Java语法冗长和缺乏类型推断(是的,我们将很快进入Scala),代码似乎非常难以阅读,难以遵循和维护。 好吧,在某种程度上,这适用于所有消息驱动的系统。 但是,只要我们不发明更好的API和原语,我们就必须学习生存并利用异步,高度并行的计算。

如果您想进一步尝试ListenableFuture ,请不要忘记阅读官方文档 。

参考: NoBlogDefFound博客中来自我们的JCG合作伙伴 Tomasz Nurkiewicz的高级ListenableFuture功能 。

翻译自: https://www.javacodegeeks.com/2013/03/advanced-listenablefuture-capabilities.html

先进的ListenableFuture功能相关推荐

  1. 堆叠式传感器架构带来先进的视觉功能

    堆叠式传感器架构带来先进的视觉功能 Stacked sensor architecture brings advanced vision capabilities 巴黎-巴黎Prophesee公司是神 ...

  2. 功能GUI编程是否可行? [关闭]

    我最近发现了FP bug(试图学习Haskell),到目前为止我已经看到了(一流的功能,懒惰的评估和所有其他好东西). 我还不是专家,但是我已经开始发现在功能上比在基本算法上强制推理更容易(而且我很难 ...

  3. c#进阶(5)—— WCF 实现简单预订功能

    1.WCF概述 WCF全称为Windows Communication Foundation,在.Net 3.0 中引入,用于客户端与服务端通信,替换了之前的一些技术,如.Net Remoting 及 ...

  4. 解读SQL Server 2012中的最新BI功能

    如果SQL Server 2008 R2的重点是让商务智能(BI)的使用者像使用自助服务一样便捷,那么SQL Server 2012则是让自助服务BI这一概念延伸至让IT人员更容易进行管理. 事实上, ...

  5. HT366 具有防破音功能的2×20W立体声D类音频功放IC

    概述 HT366是一款高效D类音频功率放大器. 在14V供电的立体声(BTL)模式.THD+N=10% 条件下,能够持续提供2*20W/4Ω功率输出:在单声道(PBTL).模式.THD+N=10%条件 ...

  6. 金雅拓推出两项全新的身份证件安全增强功能

    在成功实施后,金雅拓将进一步投资于彩色激光雕刻技术以加强欺诈保护和简化验证过程 阿姆斯特丹-- (美国商业资讯) --数字安全领域的全球领导者金雅拓(Gemalto,Euronext NL000040 ...

  7. 图像多功能实时智能处理产品——西安恒景通视觉科技有限公司

    公司简介 西安恒景通视觉科技有限公司是一家以互联网为载体,面向全国,提供人工智能与计算机视觉软件综合服务平台的高科技研发公司.公司现有研发人员70余人,具有较强的科研开发能力,特别是在智能图像信息处理 ...

  8. 渲染服务器自动渲染软件有哪些,BIM渲染软件有哪些?Keyshot渲染软件及功能简介...

    一.软件介绍 keyshot8是一款专业的3D渲染工具,这款软件渲染速度快效果好,而且操作也十分简单.keyshot8让您的工作流程更加流畅,从导入到最终渲染,这些功能能够让您前所未有地快速创建视觉效 ...

  9. python keyshot_KeyShot7:强大的功能改进!

    提高工作流程效率 KeyShot软件的渲染速度从始至终一直很快,而且操作简单.KeyShot 7延续了这一点,让您的工作流程更加流畅,从导入到最终渲染,这些功能能够让您前所未有地快速创建视觉效果. 室 ...

最新文章

  1. HDU - 5876 Sparse Graph 2016 ACM/ICPC 大连网络赛 I题 bfs+set+补图最短路
  2. android如何实现开机自动启动Service或app
  3. Swiper使用心得
  4. 《啊哈!算法》笔记_Day02
  5. 现在编程语言的两大主流
  6. UVALive 3942 Remember the Word(字典树+DP)
  7. php判断数组中的键是否是某个字符串,php判断数组中是否存在指定键(key)的方法...
  8. Delphi在代码编辑栏按回车无法换行
  9. R语言——基础知识呕心沥血大汇总
  10. 阿里巴巴编程考试认证java编程规范+考试分享
  11. TextView属性设置
  12. 阿里云域名解析ip地址变更后不起作用
  13. 大数据、云计算将催生IT产业大革命
  14. 阿里云直播服务拉流地址播放不出来
  15. bam文件读取_科学网—Pacbio Sequel两种bam文件解析 - 卢锐的博文
  16. 几行Python代码画皮卡丘
  17. 分区命令详解:用Fdisk命令硬盘分区
  18. Multisim基础 发光二极管 添加元件的位置
  19. p语言是python吗-python编程语言是什么?它能做什么?
  20. vue 2.0使用tinymce-vue富文本

热门文章

  1. 登录系统 提示框_实物资产管理软件操作手册(职员和系统用户)
  2. 圆心角 圆弧上点坐标_数控加工中心CNC的G02/G03圆弧指令的I、J、与R的区别
  3. 8.2-指令周期(学习笔记)
  4. java运行环境变量及自定义变量
  5. 代理模式(多线程实现状态监控)
  6. flutter调用api_如何在Flutter(REST API)中进行API调用
  7. okta-spring_通过Okta的单点登录保护Spring Boot Web App的安全
  8. 视图中::text_新CalendarFX视图:MonthGridView!
  9. jooq 配置oracle_jOOQ配置
  10. 您的JVM是否泄漏文件描述符-像我的一样?