正如我所理解的Akka并行性,要处理每个传入的消息Actor使用一个线程。这个线程包含一个状态。同样,顺序消息并不共享这种状态。
但是Actor可能有一个用于执行来自未来的回调的ExecutorContext。这就是我停止理解并行性的关键。
例如,我们有以下演员:
class AnyActor(target: ActorRef) extends Actor {
implicit val ec: ExecutionContext = context.dispatcher
def receive = {
case messageA =>
val api = createApi()
val furureA: Future[F] = api.callA
api.close()
futureA.pipeTo(sender())
case messageB =>
val api = createApi()
val furureB: Future[F] = api.callB
api.close()
futureB.pipeTo(sender())
}
}假设Actor接收messageA,Thread1创建api的实例--让我们调用"api1“。还有一个有N个线程的executionContext。其中一个线程用于从furureA检索结果。
我不明白的是,这N个线程是如何与Thread1相关的。ExecutionContext只为Thread1创建?或者它也是为Thread2创建的( messageB在其中处理)?
发布于 2021-11-27 18:23:56
一般而言,参与者在调度程序上运行,该调度程序从池中选择线程,并运行该参与者的Receive,以获取邮箱中的某些消息。一般来说,不能保证一个参与者会在给定的线程上运行(忽略一个空的例子,比如具有单个线程的池,或者总是在特定线程中运行给定参与者的调度程序)。
该调度程序也是Scala ExecutionContext,它允许将任意任务调度到线程池上执行;这些任务包括Future回调。
那么,在你的演员中,当收到一个messageA时会发生什么呢?
参与者调用api
api
callA方法,在发送方
callA的结果,现在可以处理另一条消息,也可能不处理另一条消息H 219F 220这实际上意味着什么取决于callA所做的工作。如果callA将任务安排在执行上下文中,那么它将在任务被调度并已安排回调后立即返回未来;无法保证在返回未来时已执行了该任务或回调。一旦返回未来,您的参与者就会关闭api (因此,这可能发生在任务执行或回调执行的任何一点上)。
简而言之,取决于api是如何实现的(而且您可能无法控制它是如何实现的)和实现细节,可以进行以下排序
dispatcher
messageA)设置任务,关闭api,并安排结果为pipedapi已关闭简而言之,当Future和演员混在一起时,Akka中的“单线程幻象”就会被打破:任意多个线程可以操纵演员的状态。
在本例中,由于Futureland和actorland之间唯一的共享状态是处理单个消息的本地状态,所以也没有那么糟糕:这里有效的一般规则是:
的存在
然后如何关闭api
那么,假设callA没有对api做任何奇怪的事情(比如在某个实例池中保存实例),在messageA完成处理并完成以后,没有任何东西可以访问api。因此,最简单,也可能也是最正确的事情是,按照以下思路,安排api在未来完成后关闭。
val api = createApi()
val futureA: Future[F] = api.callA
futureA.foreach { _ => api.close() }
futureA.pipeTo(sender()) https://stackoverflow.com/questions/70137297
复制相似问题