我想从我自己的线程与Akka演员互动。目前,我喜欢这样:
val res = Await.result(aref ? GroupReceive(fromRank), timeout.duration).asInstanceOf[T]
但我不确定这实际上是如何与我的线程交互的?我希望接收是异步的,即我想在接收时挂断线程以允许完成其他一些工作。我刚刚读到了有关Akka收件箱系统的信息。 inbox akka api
我想我曾经记得Await每次创造一个新演员。 await + ask和inbox之间有什么区别,有人可以给我一个如何创建收件箱并使用它与“外部”演员交流的例子吗?
修改 只是为了澄清,我不希望相同的线程继续工作,我希望它停止占用cpu-core并让其他线程工作直到它收到一些东西,然后再次唤醒。 / p>
答案 0 :(得分:8)
如Akka的Future文档中所述,使用Await会阻止当前线程,直到等待结果为止。
实施例
import scala.concurrent.Await
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
implicit val timeout = Timeout(5 seconds)
val future = actor ? msg // enabled by the “ask” import
val result = Await.result(future, timeout.duration).asInstanceOf[String]
这将导致当前线程阻止并等待Actor“完成” Future以及它的回复。
答案 1 :(得分:4)
Await.receive
是Scala并发API的一部分,与actor无关。它的目的是阻止当前线程,直到提供的未来完成,或者超时限制启动并且整个事件以超时异常结束。
ask运算符?
确实会创建一个临时actor,其唯一目的是等待aref
变量指向的actor的回复,并完成你在调用ask时得到的未来收到回复的运营商。
所以你的代码基本上阻止了整个线程。如上所示,如果你想释放当前的线程并继续做其他工作,你可以附加一个回调给未来。
implicit val ctx: ExecutionContext = //provide execution context here
implicit val timeout: Timeout = // provide timeout here
aref ? GroupReceive(fromRank)) onSuccess { res =>
//do something with res here, asynchronously
}
// some other code which runs without being blocked...
上面的代码可以用上面提到的演员DSL重写:
import akka.actor.ActorDSL._
implicit val actorSystem: ActorSystem = // provide an actor system here or any actor ref factory
actor(new Act {
aref ! GroupReceive(fromRank)
context.setReceiveTimeout(timeout) //optional
become {
case ReceiveTimeout => {
//handle the timeout
context.stop(self)
}
case res => {
//do your thing with res, asynchronously
context.stop(self)
}
}
}
//some other code which won't wait for the above operations
后一个版本还创建了一个新的临时actor,它发送GroupReceive
消息,然后等待回复,然后它自杀。
最重要的是,为了接收来自演员的消息,您必须自己是演员。演员不能只将消息发送到ActorRef
以外的其他内容。
所以要么你使用ask模式在幕后创建一个临时演员并管理这个临时演员的生命周期本身,向你展示一个很好的简单未来,或者你可以自己创建临时演员,但是你必须管理它的生命周期(即记得在它完成工作后杀死它)
选择最适合您的选项。
答案 2 :(得分:0)
如果您不想在主叫方上阻止,则不要使用Await,请使用非阻塞回调,例如onSuccess,onFailure和onComplete。当你这样做时,未来的任务被放入在ask(?)的范围内ExecutionContext的范围内。收到响应时,将通过ExecutionContext异步调用此回调。这样就可以避免在向actor发出请求的线程中阻塞所有进程,然后在与ExecutionContext绑定的线程池中处理回调。
此外,我相信你提到的收件箱内容是为了测试REPL中的演员内容(至少是ActorDsl上的文档)。坚持使用来自演员之外的问题的方法。让akka创建一个短暂的演员,它需要进行非演员和演员之间的沟通。然后按照我的建议切换到非阻塞回调。我相信这就是你要找的东西。