将参与者消息分配给调度程序线程



众所周知,Dispatcher线程负责执行actor消息。使用吞吐量参数,我们可以定义在转移到另一个参与者之前由调度器线程处理的消息数量

但我不确定调度线程将如何选择演员?

比方说,我创建了10000个参与者,其中一次只有1000个参与者接收消息,其余9000个参与者处于空闲状态,调度器线程数为200。

调度器线程将按照哪个顺序选择参与者的消息。它是否也会检查空闲参与者邮箱中的消息?

有人能解释一下调度程序线程选择参与者邮箱消息的流程吗。

Lightbend讨论论坛的X-Post:https://discuss.lightbend.com/t/actor-message-allocation-to-dispatcher-thread/6314

在我开始之前,简短的回答是"别担心"。我理解这种安全性,但从微观层面来说,它是不确定的,从宏观层面来说,您只需要关心Dispatcher文档中的内容,例如常规调度器、固定调度器、fork-join和线程池执行器之间的差异,以及Messaging ordering文档中的排序保证。

此外,免责声明,我并不声称自己是调度员内部的专家:我只是一个最终用户。但我有点拖延,我想我会分享一些调优观察结果,并在Akka源代码中找点乐子。要获得更详细的答案,您还应该查看来源。您正在寻找的大多数答案都将在akka-aactor/src/main/scala/akka/dedispatch文件夹中。

抛开免责声明,让我先回答你的第二个问题。

"[调度程序]是否也会检查消息的空闲参与者邮箱?">

调度员实际上并没有检查任何东西:它完全是被动的。(我们稍后会看到。)检查空邮箱肯定不会浪费任何时间。这就是为什么一个调度员可以扩展到数百万演员的原因。

您更通用的问题"调度线程将如何选择参与者?"很难用简单的方式回答。调度员的类型太多了。我能给你的每一个答案都会有一个例外。(例如,前面提到的固定调度器,其中线程专用于特定的参与者,以及CallingThreadDispatcher,它是为测试并在当前线程上运行所有调用而设计的)。但让我谈谈典型情况下的典型调度员。

调度器不挑选参与者,调度器(在典型情况下)只是Java ExecutitorServices的接口。典型的场景如下:

  • 您将邮件添加到参与者的邮箱中。(从调度员的角度来看,我们对世界的看法是颠倒的:我们与邮箱互动,而不是与参与者互动。)
  • 如果邮箱尚未安排(如果邮箱中有邮件,则可能已经安排好了),则邮箱会转到其调度程序并自行安排
  • 调度程序转到底层的ExecutorService(比方说ForkJoinExecutor),并将任务排入队列以处理邮箱
  • Java ForkJoinExecutor是一个复杂的日程安排,我并不自称是专家。但简短的版本是,每个线程都有自己的队列,但当它有一个空队列时,它能够从其他队列"窃取"任务。Java实现还能够动态调整使用的线程数,以达到并行度限制。这就是为什么我说"在微观层面"是不确定的。工作窃取动态线程是非常有效的,但它不是确定性的
  • 在某个时刻,执行器将选择与包含消息的邮箱相关的任务,并调用Runnable
  • Runnable将首先处理邮箱中的系统消息,然后处理常规消息。这里也有各种例外,如优先级邮箱、存储、吞吐量限制等。但通常情况下,邮箱会处理消息(使用参与者的行为),直到邮箱为空或达到吞吐量限制之一。请注意,任务绑定到邮箱,而不是邮件

上面的内容过于简单,忽略了一些边缘情况和性能优化,但这是30000英尺的视图。

我希望这会有所帮助,因为我知道它既充满了异常(邮箱和调度员的设计是灵活的),也很复杂。但阿卡是高度优化和疯狂的效率。如果任何一个阿卡开发人员想介入,告诉我我的描述哪里不严谨,请放心。但最终的结果就是我开始的地方:这里有多层抽象,所以你得到的唯一排序保证是有文档记录的,但即使每条消息完成的工作量很小,消息数量很大,整个系统的吞吐量也非常高效。

最新更新