actor同时处理多条消息

时间:2017-07-31 13:24:19

标签: scala akka

我知道actor模型的一个优点是,通过一次只处理一条消息,简化了并发问题。但在我看来,我的演员正在处理多条消息。在伪代码我有

var status = 0
def receive = {
  case DoSomething => 
    val dest = sender()
    status = 0

    for {
      otherActor <- resolveOtherActor("/user/OtherActor")
    } yield {
      for {
      res <- {status = 1
              otherActor ? doSomething1
              }
      res <- {status = 2
              otherActor ? doSomething2
              }
      } yield {
        dest ! status
      }
    }

  case GetStatus => sender() ! status
}

如果我向此actor发送DoSomething消息,然后立即重复向此actor发送GetStatus,我将看到状态0,1和2按顺序返回。如果actor模型一次只处理一条消息,我只会看到状态2被返回,因为我无法访问中间状态。

似乎演员模式仍然需要锁定。我错过了什么?

1 个答案:

答案 0 :(得分:5)

当你关闭一个actor的可变状态并将它暴露给其他线程时,所有的注意都会被关闭,这是你的代码在(嵌套的){{1}中变异status时所做的事情。 }。 Akka documentation明确警告不要这样做。

演员一次处理一条消息:

Future

从同一发件人向上述演员发送var status = 0 def receive = { case IncrementStatus => status += 1 case GetStatus => val s = status sender ! s } ,另一个IncrementStatus,然后IncrementStatus条消息将导致该发件人收到GetStatus

但是,尝试使用2 s做同样的事情并不能保证相同的结果,因为Future是异步完成的。例如:

Future

我们object NumService { // calculates arg + 1 in the future def addOne(arg: Int): Future[Int] = { Future { arg + 1 } } } class MyActor extends Actor { var status = 0 def receive = { case IncrementStatusInFuture => val s = status NumService.addOne(s) .map(UpdateStatus(_)) .pipeTo(self) case UpdateStatus(num) => status = num case GetStatus => val s = status sender ! s } } mapFuture创建一个Future[UpdateStatus],然后pipe为行为者Future的结果。

如果我们向同一位发件人发送IncrementStatusInFuture,另一个IncrementStatusInFuture,然后发送GetStatusMyActor邮件,我们无法保证发件人会收到2 1}}。 actor按顺序处理这三个消息,但是当actor处理NumService.addOne消息时,对GetStatus的一个或两个调用可能尚未完成。这种不确定行为是Future的特征;它并不违反一次一个消息处理的行为者原则。