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

Sou*_*nta 7 scala future actor akka

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

MyActor extends Actor 
{
.... 

def receive = {

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

}

}
Run Code Online (Sandbox Code Playgroud)

现在,由于Future非阻塞的演员会之后已停止(?),即使Future还没有完成.在这种情况下,预期的行为是什么?

举例来说,如果我有一onCompleteFuture,将是有史以来被即使演员已停止执行?

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 
    } 

}

}
Run Code Online (Sandbox Code Playgroud)

yǝs*_*ǝla 9

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

完成这个未来的执行与开始活着的演员无关.

如果您不再需要该演员,则无需等待Future完成,您可以像第一个示例中那样停止演员.

如果您需要在该actor中执行具有该未来结果的操作,则可以onComplete在该Future上安装回调.一旦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
}
Run Code Online (Sandbox Code Playgroud)

编辑

注释中建议的另一种替代方法是使用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
}
Run Code Online (Sandbox Code Playgroud)

以下是在创建Future之后可以调用它的方法:

p pipeTo myActor
Run Code Online (Sandbox Code Playgroud)

您的演员在接收消息后必须关闭自己的主要区别,并且失败显然会通过Failure消息传达给演员.使用此方法更安全,因为您必须传递一个,ActorRef而不必记住将其(自身)复制到变量中.

  • 您应该使用pipeTo模式:`import akka.pattern.pipe p.pipeTo(self)` (2认同)