分配给调度程序线程的 Actor 消息分配
Actor message allocation to dispatcher thread
已知 Dispatcher 线程负责执行 actor 消息。使用吞吐量参数我们可以定义没有。在移动到另一个参与者之前由调度程序线程处理的消息数
但我不确定调度程序线程将如何选择演员?
比如说,我创建了 10,000 个 actor,其中只有 1000 个 actor 一次接收消息,其余 9000 个 actor 空闲,调度程序线程数为 200。
调度程序线程将按什么顺序挑选演员的消息。是否会检查空闲演员邮箱是否也有消息?
任何人都可以解释调度程序线程挑选参与者邮箱消息的流程。
X-Post 来自 Lightbend 的讨论论坛:https://discuss.lightbend.com/t/actor-message-allocation-to-dispatcher-thread/6314
在我开始之前,简短的回答是 "don't worry about it"。我理解这种好奇心,但在微观层面上它是不确定的,而从宏观层面来看,你唯一需要关心的事情在 Dispatcher documentation such as the difference between regular dispatchers, pinned dispatchers, fork-join, and thread pool executors and in the ordering guarantees in the Messaging Ordering 文档中。
此外,免责声明,我并不声称自己是调度程序内部的专家:我只是最终用户。但我有点拖延,我想我会分享一些我的调优观察结果,并为了好玩而浏览一下 Akka 源代码。要获得更详细的答案,您还应该查看源代码。您要查找的大部分答案都在 akka-actor/src/main/scala/akka/dispatch 文件夹中。
先排除免责声明,让我先回答你的第二个问题。
"Whether [the dispatcher] will check for idle actors mailbox also for the messages?"
调度程序实际上不检查任何东西:它完全是被动的。 (我们稍后会看到。)它当然不会浪费任何时间检查空邮箱。这就是为什么单个调度程序可以扩展到数百万个演员。
您的更笼统的问题 "how dispatcher thread will pick the actor?" 很难以简单的方式回答。调度员有很多种。几乎我能给你的每一个答案都会有例外。 (例如,前面提到的固定调度程序,其中线程专用于特定的参与者,而 CallingThreadDispatcher 设计用于测试并在当前线程上运行所有调用)。但是我来说说典型情况下的典型调度员。
调度程序不选择参与者,调度程序(在典型情况下)只是 Java ExecutorServices 的接口。典型场景如下所示:
- 您向演员的邮箱添加了一条消息。 (从调度员的角度来看,我们有一个倒置的世界观:我们与邮箱互动,而不是演员。)
- 如果邮箱尚未安排(如果其中有邮件,则可能已经安排),邮箱将转到其调度程序并自行安排。
- 调度程序转到底层 ExecutorService(比方说 ForkJoinExecutor)并排队处理邮箱的任务。
- A Java ForkJoinExecutor is a complicated piece of scheduling 而且我不自称是专家。但简短的版本是每个线程都有自己的队列,但是当它有一个空队列时,它能够从其他队列中执行 "stealing" 任务。 Java 实现还能够动态调整它正在使用的线程数以达到并行度限制。这就是为什么我说 "at the micro level" 它是不确定的。窃取动态线程的工作非常有效,但它不是确定性的。
- 在某些时候,与包含消息的邮箱相关的任务将由执行程序选择,并将调用 Runnable。 .
- Runnable 将首先处理邮箱中的系统消息,然后处理常规消息。这里也有各种例外,如优先邮箱、存储、吞吐量限制等。但通常邮箱会处理消息(使用参与者的行为),直到邮箱为空或达到吞吐量限制之一。请注意,任务是绑定到邮箱而不是消息。
以上过于简单,忽略了一些边缘情况和性能优化,但那是 30,000 英尺的视图。
我希望这对您有所帮助,因为我知道它充满了异常(邮箱和调度程序的设计很灵活)而且很复杂。但是 Akka 是高度优化的并且非常高效。如果任何 Akka 开发人员想介入,请告诉我我的描述哪里草率了,请随意。但最终结果是我开始的地方:这里有多层抽象,所以你得到的唯一顺序保证是记录的那些,但即使每条消息完成的工作很小并且消息数量是巨大。
已知 Dispatcher 线程负责执行 actor 消息。使用吞吐量参数我们可以定义没有。在移动到另一个参与者之前由调度程序线程处理的消息数
但我不确定调度程序线程将如何选择演员?
比如说,我创建了 10,000 个 actor,其中只有 1000 个 actor 一次接收消息,其余 9000 个 actor 空闲,调度程序线程数为 200。
调度程序线程将按什么顺序挑选演员的消息。是否会检查空闲演员邮箱是否也有消息?
任何人都可以解释调度程序线程挑选参与者邮箱消息的流程。
X-Post 来自 Lightbend 的讨论论坛:https://discuss.lightbend.com/t/actor-message-allocation-to-dispatcher-thread/6314
在我开始之前,简短的回答是 "don't worry about it"。我理解这种好奇心,但在微观层面上它是不确定的,而从宏观层面来看,你唯一需要关心的事情在 Dispatcher documentation such as the difference between regular dispatchers, pinned dispatchers, fork-join, and thread pool executors and in the ordering guarantees in the Messaging Ordering 文档中。
此外,免责声明,我并不声称自己是调度程序内部的专家:我只是最终用户。但我有点拖延,我想我会分享一些我的调优观察结果,并为了好玩而浏览一下 Akka 源代码。要获得更详细的答案,您还应该查看源代码。您要查找的大部分答案都在 akka-actor/src/main/scala/akka/dispatch 文件夹中。
先排除免责声明,让我先回答你的第二个问题。
"Whether [the dispatcher] will check for idle actors mailbox also for the messages?"
调度程序实际上不检查任何东西:它完全是被动的。 (我们稍后会看到。)它当然不会浪费任何时间检查空邮箱。这就是为什么单个调度程序可以扩展到数百万个演员。
您的更笼统的问题 "how dispatcher thread will pick the actor?" 很难以简单的方式回答。调度员有很多种。几乎我能给你的每一个答案都会有例外。 (例如,前面提到的固定调度程序,其中线程专用于特定的参与者,而 CallingThreadDispatcher 设计用于测试并在当前线程上运行所有调用)。但是我来说说典型情况下的典型调度员。
调度程序不选择参与者,调度程序(在典型情况下)只是 Java ExecutorServices 的接口。典型场景如下所示:
- 您向演员的邮箱添加了一条消息。 (从调度员的角度来看,我们有一个倒置的世界观:我们与邮箱互动,而不是演员。)
- 如果邮箱尚未安排(如果其中有邮件,则可能已经安排),邮箱将转到其调度程序并自行安排。
- 调度程序转到底层 ExecutorService(比方说 ForkJoinExecutor)并排队处理邮箱的任务。
- A Java ForkJoinExecutor is a complicated piece of scheduling 而且我不自称是专家。但简短的版本是每个线程都有自己的队列,但是当它有一个空队列时,它能够从其他队列中执行 "stealing" 任务。 Java 实现还能够动态调整它正在使用的线程数以达到并行度限制。这就是为什么我说 "at the micro level" 它是不确定的。窃取动态线程的工作非常有效,但它不是确定性的。
- 在某些时候,与包含消息的邮箱相关的任务将由执行程序选择,并将调用 Runnable。 .
- Runnable 将首先处理邮箱中的系统消息,然后处理常规消息。这里也有各种例外,如优先邮箱、存储、吞吐量限制等。但通常邮箱会处理消息(使用参与者的行为),直到邮箱为空或达到吞吐量限制之一。请注意,任务是绑定到邮箱而不是消息。
以上过于简单,忽略了一些边缘情况和性能优化,但那是 30,000 英尺的视图。
我希望这对您有所帮助,因为我知道它充满了异常(邮箱和调度程序的设计很灵活)而且很复杂。但是 Akka 是高度优化的并且非常高效。如果任何 Akka 开发人员想介入,请告诉我我的描述哪里草率了,请随意。但最终结果是我开始的地方:这里有多层抽象,所以你得到的唯一顺序保证是记录的那些,但即使每条消息完成的工作很小并且消息数量是巨大。