Actor与并发

Future:(用来存放将来可能成功或失败的结果)的使用
Scala中,这个特殊值称为Future。Future是一种占位符,即某个值的内存位置。当创建Future时,相应的占位符中不需要有值;可以随着方法的执行,在未来的某个时间将值放进去。

一、响应式四准则

设计目标:灵敏性、伸缩性、容错性、事件驱动性

二、剖析Actor

1、 AbstractActor:首先,我们继承了AbstractActor

2、 Receive:AbstractActor 类有一个receive 方法,其子类必须实现这个方法或是通过构造函数调用该方法。receive 方法返回的类型是PartialFunction。

Akka 为我们提供了一个抽象的构造方法类receiveBuilder,用于生成PartialFunction 作为返回值。

3、 receiveBuilder:连续调用receiveBuilder 的方法,为所有需要匹配处理的输入消

息类型提供响应方法的描述, 然后调用build() 方法生成需要返回的PartialFunction

4、 Match:receiveBuilder 提供了一些值得一提的match 方法,我们将提供一些示例,展示如何分别使用这些方法来匹配“ping”消息。

(1)match(class, function):描述了对于任何尚未匹配的该类型的示例,应该如何响应。

 match(String.class, s -> {if(s.equals("Ping")) respondToPing(s);})

(2)match(class, predicate, function):描述了对于predicate 条件函数为真的某特定类型的消息,应该如何响应。

 match(String.class, s -> s.equals("Ping"), s -> respondToPing(s))

(3)matchEquals(object, function):描述了对于和传入的第一个参数相等的消息,应该如何响应。

 matchEquals("Ping", s -> respondToPing(s))

(4) matchAny(function):该函数匹配所有尚未匹配的消息。通常来说,最佳实践是返回错误信息,或者至少将错误信息记录到日志,帮助开发过程中的错误调试。

match 函数从上至下进行模式匹配。所以可以先定义特殊情况,最后定义一般情况。

java

receiveBuilder
.matchEquals("Ping", s -> System.out.println("It's Ping: " + s))
.match(String.class, s -> System.out.println("It's a string: " + s))
.matchAny(x -> System.out.println("It's something else: " + x))
.build

scala

def receive = {
    case s:String if s.equalsIgnoreCase("Ping") => println("It's Ping: " + s)
    case s:String => println("It's a string: " + s)
    case x:Any => println("It's something else: " + x)
  }

向sender()返回消息:调用了sender()方法后,我们就可以返回所收到的消息的响应了。响应的对象既可能是一个Actor也可能是来自于Actor 系统外部的请求

第一种情况相当直接:返回的消息会直接发送到该Actor 的收件信箱中

tell():sender() 函数会返回一个ActorRef。在上面的例子中,我们调用了sender().tell()

tell()是最基本的单向消息传输模式。第一个参数是我们想要发送至对方信箱的消息。

第二个参数则是希望对方Actor 看到的发送者。

和第1 章初识Actor 中使用过的方法类似,我们描述了接收到的消息是String

时应该做出的响应。由于需要检查接收到的字符串是否为“Ping”,因此需要进行判断,所以这里使用的match 方法略有不同。然后描述响应行为:通过tell()方法向sender()返回一条消息。我们返回的消息是字符串“Pong”。Java 的tell方法要求提供消息发送者的身份:这里使用ActorRef.noSender()表示没有返回地址。

返回akka.actor.Status.Failure:为了向发送方报告错误信息,需要向其发送一条消息。如果Actor 中抛出了异常,就会通知对其进行监督的Actor(将在第3 章传递消息中进行介绍)。不过无论如何,如果想要报告错误消息,需要将错误发送给发送方。如果发送方使用Future 来接收响应,那么返回错误消息会导致Future 的结果为失败。

三、Actor的创建

访问Actor 的方法和访问普通对象的方法有所不同。我们从来都不会得到Actor 的实例,从不调用Actor 的方法,也不直接改变Actor 的状态,反之,只向Actor 发送消息。

除此之外,我们也不会直接访问Actor 的成员,而是通过消息传递来请求获取关于Actor状态的信息。

在Akka 中,这个指向Actor 实例的引用叫做ActorRef。ActorRef 是一个无类型的引用,将其指向的Actor 封装起来,提供了更高层的抽象,并且给用户提供了一种与Actor进行通信的机制。

Actor 系统就是包含所有Actor 的地方。有一点可能相当明显:我们也正是在Actor 系统中创建新的Actor 并获取指向Actor 的引用。actorOf 方法会生成一个新的Actor,并返回指向该Actor 的引用。
在Scala中的三种创建方式,推荐在单例模式创建工厂方法,这样Actor实例不会被闭包捕获

	def props(hello: String) = Props(new HelloActor(hello))

    def propsAlt(hello: String) = Props(classOf[HelloActor], hello)

    def noParameterPropsAlt = Props(classOf[HelloActor])
四、Props

为了保证能够将Actor 的实例被封装起来,不让其被外部直接访问,我们将所有构造函数的参数传给一个Props 的实例。Props 允许我们传入Actor 的类型以及一个变长的参数列表。

 Props.create(classOf[Nothing], arg1, arg2, argn)

actorOf 创建一个Actor,并返回指向该Actor 的引用ActorRef。除此之外,还有另一种方法可以获取指向Actor 的引用:actorSelection。

回顾:

我们可以创建一个Actor,传入一个构造参数列表构

建一个Props 实例,并将该Props 实例作为参数传给system.actorOf 并调用system.actorOf方法,得到指向该Actor 的引用。要为Actor 指定名字的话,只需要将该名字作为参数传给actorOf 方法即可。最后,我们可以使用actorSelection 在本地或远程系统上查找已有的Actor。

五、Promise、Future 和事件驱动的编程模型

1、 阻塞与事件驱动API

简单的使用阻塞IO 调用数据库的例子:

String username = getUsernameFromDatabase(userId);
System.out.println(username);

**“事件驱动”**这个术语正是描述了这种方法:在发生某些特定事件时,就执行某些对应的代码有一点必须要再次强调:打印语句并不会运行在进行事件注册的线程上。它会运行在另一个线程上,该线程信息由ExecutionContext 维护。Future 永远是通过Execution Context来创建的,因此我们可以选择在哪里运行Future 中真正需要执行的代码。

2、 使用Future 进行响应的Actor首先创建一个ActorSystem,然后通过actorOf 在刚创建的Actor 系统中创建一个Actor

ActorSystem system = ActorSystem.create();
ActorRef actorRef = system.actorOf(Props.create(JavaPongActor.class));

现在向Actor 询问其对于某个消息的响应:

final Future sFuture = ask(actorRef, "Ping", 1000);

我们调用ask 方法,传入以下参数:

消息发送至的Actor 引用;
想要发送给Actor 的消息;
Future 的超时参数:等待结果多久以后就认为询问失败。

ask 会返回一个Scala Future,作为响应的占位符。在Actor 的代码中,Actor 会向sender()发送回一条消息,这条消息就是在ask 返回的Scala Future 中将接收到的响应。

虽然我们无法在Java 8 中使用Scala Future,但是可以通过之前导入的库将其转换为

CompletableFuturefinal CompletionStage<String> cs = toJava(sFuture);
final CompletableFuture<String> jFuture = (CompletableFuture<String>) cs;

最后,我们调用get()方法将测试线程阻塞,并得到结果。在查询失败的例子中,get

方法会抛出一个从Actor 发送出的akka.status.Failure 异常。

六、理解Future 和Promise

1、 Future——在类型中表达失败与延迟

2、 构造消息:

Get 消息:如果key 存在,就返回value;

Key Not Found 异常消息:如果key 不存在,就返回该异常;

Set 消息:设置某个键值对,返回状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值