Akka TypedActor - 如何正确处理上下文的异步响应

时间:2014-04-26 03:23:08

标签: scala akka actor typedactor

我已经开始在Scala中使用TypedActors并且遇到了一个非常简单的问题:我希望Actor A在Actor B上调用一个方法并在Actor A上的匿名函数中处理结果,但要确保:< / p>

  1. 我的响应处理功能是线程安全的,例如不会与访问Actor A状态的任何其他线程同时运行
  2. 我的响应处理函数可以引用Actor A的上下文

我怎样(或者我可以)满足这两个要求?

例如,这个actor只想调用返回Future [Int]的otherActor上的API,并用结果更新它的状态,然后做一些需要它的actor的上下文: / p>

class MyActorImpl extends MyActor {

  // my mutable state
  var myNumber = 0

  // method proxied by TypedActor ref:
  def doStuff(otherActor: OtherActor): Unit = {
    otherActor.doOtherStuff onSuccess {
      // oops this is no longer running in MyActorImpl..
      // this could be on a concurrent thread if we
      case i => processResult(i)
    }
  }

  private def processResult(i: Int): Unit = {
    myNumber = 0 // oops, now we are possibly making a concurrent modification
    println(s"Got $i")

    // fails with java.lang.IllegalStateException: Calling TypedActor.context
    // outside of a TypedActor implementation method!
    println(s"My context is ${TypedActor.context}")
  }
}

我在这里缺少什么?我是否需要编写处理程序来调用代理接口上定义的方法以保证单项?如果我不想在接口上公开那个特定的“私有”方法(例如processResult),这看起来很难看。

这是一个将在Scala REPL中运行的完整版本:

import akka.actor._
import scala.concurrent._

val system = ActorSystem("mySystem")
import system.dispatcher

trait OtherActor {
  def doOtherStuff(): Future[Int]
}


trait MyActor {
  def doStuff(otherActor: OtherActor): Unit
}

class OtherActorImpl extends OtherActor {
  var i = 0
  def doOtherStuff(): Future[Int] = {
    i += 1
    Future {i} 
  }
}

class MyActorImpl extends MyActor {

  // my mutable state
  var myNumber = 0

  // method proxied by TypedActor ref:
  def doStuff(otherActor: OtherActor): Unit = {
    otherActor.doOtherStuff onSuccess {
      // oops this is no longer running in MyActorImpl..
      // this could be on a concurrent thread if we
      case i => processResult(i)
    }
  }

  private def processResult(i: Int): Unit = {
    myNumber = 0 // oops, now we are possibly making a concurrent modification
    println(s"Got $i")

    // fails with java.lang.IllegalStateException: Calling TypedActor.context
    // outside of a TypedActor implementation method!
    println(s"My context is ${TypedActor.context}")
  }
}

val actor1: MyActor = TypedActor(system).typedActorOf(TypedProps[MyActorImpl])
val actor2: OtherActor = TypedActor(system).typedActorOf(TypedProps[OtherActorImpl])

actor1.doStuff(actor2)

1 个答案:

答案 0 :(得分:1)

你正在向外界揭露演员的状态,这是一件非常糟糕的事情。请看这里:http://doc.akka.io/docs/akka/2.3.3/general/jmm.html部分参与者和共享可变状态第9-10行描述您的情况。

@philwalk已经描述了如何解决这个问题:Akka TypedActor - how to correctly handle async responses with context