在receive方法中调用Future并在此之后停止actor

时间:2014-07-22 04:14:45

标签: scala akka actor future

我创造了一群做一些工作的演员,然后他们就被制止了。在其中一些演员中,我调用了返回Future的第三方API。

MyActor extends Actor 
{
.... 

def receive = {

   case MsgA => {
    ... 
    //this evaluates to a Future
    val p : Future = someFutureAPICall()
    //stop the actor 
    context stop self 
    } 

}

}

现在由于Future 非阻塞,即使Future尚未完成,演员也会在此之后(?)停止。在这种情况下,预期的行为是什么?

例如,如果onComplete上有Future,即使演员已经停止,也会执行吗?

MyActor extends Actor 
{
.... 

def receive = {

   case MsgA => {
    ... 
    //this evaluates to a Future
    val p : Future = someFutureAPICall()

    p.onComplete {
      //will these expressions ever be evaluated ? 
      case Success(x) => log.info("Success")
      case Failure(f) => log.info("Failure") 
    }
    //stop the actor 
    context stop self 
    } 

}

}

1 个答案:

答案 0 :(得分:8)

是的,返回Future(第三方API)的代码将立即执行并返回不完整的Future。

完成这个未来的执行与开始活着的演员没有任何关系。

如果你不再需要那个演员,你就不需要等待未来完成,你可以像第一个例子那样停止演员。

如果您需要在该actor中执行具有该未来结果的操作,您可以在该Future上安装onComplete回调。一旦Future完成,它可以向演员发送消息以停止。例如:

val myActor = self // Don't close over unstable actor reference by using self directly
p.onComplete {
  case Success(x) => myActor ! x; myActor ! akka.actor.PoisonPill // sends result to be processed and then stops actor
  case Failure(f) => myActor ! akka.actor.PoisonPill // stops actor
}

修改

评论中建议的另一种方法是使用pipeTo使用模式。它几乎完全相同。以下是它在Akka库中的实现方式:

def pipeTo(recipient: ActorRef)(implicit sender: ActorRef = Actor.noSender): Future[T] = {
  future onComplete {
    case Success(r) ⇒ recipient ! r
    case Failure(f) ⇒ recipient ! Status.Failure(f)
  }
  future
}

以下是在创建Future之后如何调用它:

p pipeTo myActor

您的演员在收到消息后必须关闭自己的主要区别,并且失败显然会通过Failure消息传达给演员。这种方法使用起来有点安全,因为你必须传递一个ActorRef并且你不必记住将它(自己)复制到一个变量中。