首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ExecutionContext对演员的理解

ExecutionContext对演员的理解
EN

Stack Overflow用户
提问于 2021-11-27 17:49:47
回答 1查看 114关注 0票数 2

正如我所理解的Akka并行性,要处理每个传入的消息Actor使用一个线程。这个线程包含一个状态。同样,顺序消息并不共享这种状态。

但是Actor可能有一个用于执行来自未来的回调的ExecutorContext。这就是我停止理解并行性的关键。

例如,我们有以下演员:

代码语言:javascript
复制
  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在其中处理)?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-27 18:23:56

一般而言,参与者在调度程序上运行,该调度程序从池中选择线程,并运行该参与者的Receive,以获取邮箱中的某些消息。一般来说,不能保证一个参与者会在给定的线程上运行(忽略一个空的例子,比如具有单个线程的池,或者总是在特定线程中运行给定参与者的调度程序)。

该调度程序也是Scala ExecutionContext,它允许将任意任务调度到线程池上执行;这些任务包括Future回调。

那么,在你的演员中,当收到一个messageA时会发生什么呢?

参与者调用api

  • It并将其保存为

  • ,它在api

  • It上调用callA方法,在发送方

  • 可用时,安排转发callA的结果,现在可以处理另一条消息,也可能不处理另一条消息H 219F 220

这实际上意味着什么取决于callA所做的工作。如果callA将任务安排在执行上下文中,那么它将在任务被调度并已安排回调后立即返回未来;无法保证在返回未来时已执行了该任务或回调。一旦返回未来,您的参与者就会关闭api (因此,这可能发生在任务执行或回调执行的任何一点上)。

简而言之,取决于api是如何实现的(而且您可能无法控制它是如何实现的)和实现细节,可以进行以下排序

dispatcher

  • Thread1中的
  • Thread1 (processing messageA)设置任务,关闭api,并安排结果为piped
  • Thread2,开始执行任务,
  • Thread1继续处理其他message
  • Thread2's任务,因为api已关闭

简而言之,当Future和演员混在一起时,Akka中的“单线程幻象”就会被打破:任意多个线程可以操纵演员的状态。

在本例中,由于Futureland和actorland之间唯一的共享状态是处理单个消息的本地状态,所以也没有那么糟糕:这里有效的一般规则是:

  • ,一旦您将可变状态(例如关闭状态)从参与者传递到未来(这包括,除非您完全确定发生了什么,调用返回未来的有状态对象的方法),最好让参与者忘记该对象

的存在

然后如何关闭api

那么,假设callA没有对api做任何奇怪的事情(比如在某个实例池中保存实例),在messageA完成处理并完成以后,没有任何东西可以访问api。因此,最简单,也可能也是最正确的事情是,按照以下思路,安排api在未来完成后关闭。

代码语言:javascript
复制
val api = createApi()
val futureA: Future[F] = api.callA

futureA.foreach { _ => api.close() }
futureA.pipeTo(sender()) 
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70137297

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档