Actors in Scala(Scala中的Actor)(预打印版) 第五章 Event-Based Programming (B)

2024-02-07 20:08

本文主要是介绍Actors in Scala(Scala中的Actor)(预打印版) 第五章 Event-Based Programming (B),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Actors in Scala(Scala中的Actor)(预打印版) 第五章 Event-Based Programming (B)

张贵宾

guibin.beijing@gmail.com


2011.10.29

注:翻译这些英文书籍资料纯属个人爱好,如有不恰当之处敬请指正。

5.3 Event-based futures(基于事件的Future)

在第四章,我们展示了如何为注重结果(result-bearing)的消息使用future。Future中一些等待结果的方法在底层都依赖基于线程的receive方法。在等待结果时,这些方法都独占了底层的线程。然而,也可以在future等待结果时使用react的基于事件的方式(,这样就不会独占底层的线程了)。


比如,假设我们要从一个指定的URL上为所有的图片渲染一个概览。我们可以在图片下载完毕后,再依次渲染每张单独的图片。为了增加程序的吞吐量,可以让每个loader用自己的actor去单独下载,既然每个执行下载的actor都执行的是注重结果的任务,那么就可以很方便的使用future来跟踪期望的结果。下面的代码就展示了用这种方式渲染图片。

def renderImages(url: String) {val imageInfos = scanForImageInfo(url)val dataFurures = for(info <- imageInfos) yield {val loader = actor {react {case Download(info) =>reply(info.downloadImage())}}loader !! Download(info)}for (i <- 0 until imageInfos.size) {dataFuture(i)() match {case data@ImageData(_) =>renderImage(data)}}println("OK, all images rendered")
}

首先,URL作为扫描图片信息的输入参数。对每一张图片,我们都启动了一个专门的actor去下载,下载完毕后把图片内容作为响应。我们使用两个惊叹号 !! 来获得发送消息之后的future。一旦所有的future都被收集到了dataFutures中,当前的actor通过依次调用future的apply无参数方法来等待结果。

例子:使用react和future的图片渲染器

我们刚才描述的实现方式在等待future的结果时将会阻塞底层的线程。然而,我们也可以使用react以非阻塞的、基于消息的方式等待future。这样做的关键是与每个future相关联的InputChannel,这个channel是用来把future的结果传输给创建future的actor。使用基于线程的receive,调用future的apply方法会等待收取这个channel上的结果。然而我们也能在future的Channel上够使用react用基于事件的方式等待结果。

def renderImages(url: String) {val imageInfos = scanForImageInfo(url)val dataFutures = for(info <- imageInfos) yield {val loader = actor {react {case Download(info) =>reply(info.downloadImage())}}loader !! Download(info)}var i = 0loopWhile(i < imageInfos.size) {i += 1dataFutures(i - 1).inputChannel.react{case data@ImageData(_) =>renderImage(data)}} andThen {println("OK, all images rendered.")}
}

上面的代码展示了刚才所说的实现。既然有必要依次调用react多次,那么就可以使用5.2节中介绍的控制流组合器。在这个例子中,我们使用loopWhile来模拟上一个实现版本的循环。其主要区别是:新版的代码声明了索引变量 i ,并且显示的自增,而且使用循环的终止条件代替了for循环的遍历。


你也可以建立一个客户化的控制流组合器来在for循环内部使用react。在下面的章节中我们将解释如何做到这一点的。

List5.9

def renderImages(url: String) {val imageInfos = scanForImageInfo(url)val dataFutures = for(info <- imageInfos) yield {val loader = actor {react {case Download(info) => reply(info.downloadImage()) }}loader !! Download(info)}(for (ft <- ForEach(dataFutures))ft.inputChannel.react {case data@ImageData(_) => renderImage(data)}  andThen {println("OK, all images rendered.")})
}


List 5.10
case class ForEach[T] (iter: Iterable[T]) {def foreach (fun: T => Unit): Unit = {val it = iter.elements // 在Scala2.9中elements方法已经废弃,使用iterator方法。 loopWhile(it.hasNext) {fun(t.next)}}
}

Building custom control-flow operators(构建客户化的控制流操作符)

有时候Actor对象提供的已经存在的控制流组合器不能很好的适应手头的任务,在这种情况下构建客户化的控制流操作符可以派上用场。在这节中,你将学到如何使用Actor对象提供的控制流组合器来构建能在for循环中使用react方法的客户化的操作符。


代码5.9展示了使用客户化的ForEach操作符遍历一个list,在遍历的同时调用每个元素的react方法。在这种情况下,我们希望遍历dataFutures中的future。我们使用ForEach把dataFutures list转换成一个类似复合for循环中的生成器对象,它生成了与dataFutures list中相同的值,也就是说生成了所有的list中的元素。然而,ForEach做到了即使在调用了for循环内部的react之后,还能够继续遍历。


代码5.10展示了ForEach的具体实现。把ForEach设计成case class主要是为了在创建实例时能够省略new关键字。ForEach的构造函数接收一个类型为Iterable[T]的参数--这个集合参数用于生成我们自己的迭代器。


ForEach类有一个唯一的方法foreach,foreach方法接收一个函数类型的参数 T => Unit,实现foreach方法使得ForEach类的实例能够在简单的for复合循环中被用作生成器,就像代码5.9中展示的那样。在复合for循环中被绑定到生成元素的变量对应于函数类型的参数fun,复合循环的循环体对应于函数类型参数fun的函数体。


在foreach方法内部,我们首先从Iterable中获得了迭代器it,然后我们使用it和loopWhile组合器遍历集合,在每一次迭代过程中,我们对当前的集合元素应用函数方法fun,既然我们在使用loopWhile,那么在fun方法中调用react就很安全。


这篇关于Actors in Scala(Scala中的Actor)(预打印版) 第五章 Event-Based Programming (B)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/688785

相关文章

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

多数据源的事务处理总是打印很多无用的log日志

之前做了一个项目,需要用到多数据源以及事务处理,在使用事务处理,服务器总是打印很多关于事务处理的log日志(com.atomikos.logging.Slf4jLogger),但是我们根本不会用到这些log日志,反而使得查询一些有用的log日志变得困难。那要如何屏蔽这些log日志呢? 之前的项目是提高项目打印log日志的级别,后来觉得这样治标不治本。 现在有一个更好的方法: 我使用的是log

fastreport打印trichedit分页问题的解决

用fastreport来打印richedit里面的内容。刚开始放一个frxrichview组件到报表上,然后在 var str: TMemoryStream; begin    begin      str:= TMemoryStream.Create;      CurrRichRecord.richedit.Lines.SaveToStream(str);      str.Posit

模具要不要建设3D打印中心

随着3D打印技术的日益成熟与广泛应用,模具企业迎来了自建3D打印中心的热潮。这一举措不仅为企业带来了前所未有的发展机遇,同时也伴随着一系列需要克服的挑战,如何看待企业引进增材制造,小编为您全面分析。 机遇篇: 加速产品创新:3D打印技术如同一把钥匙,为模具企业解锁了快速迭代产品设计的可能。企业能够迅速将创意转化为实体模型,缩短产品从设计到市场的周期,抢占市场先机。 强化定制化服务:面

React第五章(swc)

swc 什么是swc? SWC 既可用于编译,也可用于打包。对于编译,它使用现代 JavaScript 功能获取 JavaScript / TypeScript 文件并输出所有主流浏览器支持的有效代码。 SWC在单线程上比 Babel 快 20 倍,在四核上快 70 倍。 简单点来说swc实现了和babel一样的功能,但是它比babel快。 FAQ为什么快? 编译型 Rust 是

fetch-event-source 如何通过script全局引入

fetchEventSource源码中导出了两种类型的包cjs和esm。但是有个需求如何在原生是js中通过script标签引呢?需要加上type=module。今天介绍另一种方法 下载源码文件: https://github.com/Azure/fetch-event-source.git 安装: npm install --save-dev webpack webpack-cli ts

Java项目中,配置打印 JDBC 日志的几种方法

在 IDEA 项目中,如果你想打印 JDBC 日志,可以通过配置日志框架(如 Logback 或 Log4j)来实现。Spring Boot 使用的默认日志框架是 Logback,你可以通过在 application.yml 文件中配置日志级别来打印 JDBC 日志。 方法 1: 使用 application.yml 配置 JDBC 日志 logging:level:# 显示 SQL 语句co

一个C++程序运行,从点击运行到控制台打印文本,电脑硬件的资源是如何调动的

当点击运行一个 C++ 程序并看到控制台输出文本时,计算机硬件和操作系统之间协同工作,完成了多个步骤。这些步骤涉及 CPU、内存、存储设备、操作系统和输入输出设备的共同作用。下面是一个详细的过程描述: 1. 程序加载 启动:当你点击运行一个可执行文件时,操作系统(通常是 Windows、Linux 或 macOS)的文件系统管理器识别请求,并启动加载程序。读取可执行文件:加载程序将可执行文件从

myEclipse失去焦点时报错Unhandled event loop exception的解决方案

一句话:百度杀毒惹的祸。。。。果断卸载后问题解决。

MACS bdgdiff: Differential peak detection based on paired four bedGraph files.

参考原文地址:[http://manpages.ubuntu.com/manpages/xenial/man1/macs2_bdgdiff.1.html](http://manpages.ubuntu.com/manpages/xenial/man1/macs2_bdgdiff.1.html) 文章目录 一、MACS bdgdiff 简介DESCRIPTION 二、用法