4

我有一个任务可以很容易地分解成可以并且应该并行处理以优化性能的部分。

我写了一个生产者actor,它准备了可以独立处理的任务的每个部分。这种制剂相对便宜。

我编写了一个消费者 Actor 来处理每个独立的任务。根据参数,每个独立任务可能需要几秒钟的时间来处理。所有的任务都是一样的。它们都处理相同的算法,具有相同数量的数据(当然是不同的值),从而导致大约相同的处理时间。

所以生产者比消费者快得多。因此,很快可能准备好 200 或 2000 个任务(取决于参数)。所有这些都消耗内存,而一次只能执行其中的几个。

现在我看到了两种简单的使用和处理任务的策略:

  1. 为每个任务创建一个新的消费者参与者实例。

    • 每个消费者只处理任务。
    • 我假设同时会有许多消费者参与者实例,而其中只有几个可以在任何时间点进行处理。
    • 默认调度程序如何工作?每个消费者参与者能否在安排下一个消费者之前完成处理?或者消费者会被打断并被另一个消费者取代,导致第一个任务完成的时间更长?我认为这个actor调度与进程或线程调度不同,但我可以想象,中断仍然有一些缺点(例如更多的缓存未命中)。
  2. 另一种策略是使用消费者参与者的 N 个实例并将要处理的任务作为消息发送给它们。

    • 每个消费者按顺序处理多个任务。
    • 由我来为 N(消费者数量)找到一个合适的值。
    • N 个消费者的任务分配也由我决定。
  3. 我可以想象一个更复杂的解决方案,在生产者和消费者之间进行更多的协调,但是如果不了解调度程序,我就无法做出好的决定。

如果手动解决方案不会显着提高性能,我更喜欢默认解决方案(由 Scala 世界的某些部分提供),其中调度任务不由我决定(如策略 1)。

问题综述:

  • 默认调度程序如何工作?
    • 每个消费者参与者能否在安排下一个消费者之前完成处理?
    • 或者消费者会被打断并被另一个消费者取代,导致第一个任务完成的时间更长?
    • 当调度器频繁中断一个actor并调度另一个actor时有什么缺点?缓存未命中?
    • 这种中断和调度会像进程调度或线程调度中的上下文变化吗?
  • 比较这些策略是否还有更多优点或缺点?
  • 尤其是策略 1 相对于策略 2 有劣势吗?
  • 这些策略中哪一个是最好的?
  • 有比我建议的更好的策略吗?

恐怕,像最后两个这样的问题不能绝对回答,但也许这次是可能的,因为我试图给出一个尽可能具体的案例。

我认为其他问题无需过多讨论即可回答。有了这些答案,应该可以选择最适合需求的策略。

我自己做了一些研究和思考,并提出了一些假设。如果这些假设中的任何一个是错误的,请告诉我。

4

3 回答 3

0

对于这样一个简单的任务,演员根本不给任何利润。将生产者实现为 Thread,将每个任务实现为 Runnable。使用 java.util.concurrent 中的线程池来运行任务。使用 java.util.concurrent。信号量限制已准备和运行的任务数量:在创建下一个任务之前,生产者获取信号量,每个任务在执行结束时释放信号量。

于 2012-11-28T02:39:45.707 回答
0

假设你正在使用 Akka(如果你不使用,你应该 ;-) ),你可以使用 aSmallestMailboxRouter来启动一些参与者(你也可以添加 a Resizer)并且消息分发将根据一些规则来处理。您可以在此处阅读有关路由器的所有信息。

于 2012-11-26T14:05:30.760 回答
0

如果我是你,我会2选择 nd 选项。为每个任务创建一个新的 actor 实例太乏味了。此外,通过智能决策N,可以使用完整的系统资源。

虽然这不是一个完整的解决方案。但是一种可能的选择是,生产者不能停止/减慢生产任务的速度吗?这将是理想的。只有当有可用的消费者或其他东西时,生产者才会产生更多的任务。

于 2012-11-26T11:13:41.503 回答