考虑延迟和效率来分配任务的最佳方式

时间:2011-11-09 13:30:55

标签: algorithm optimization multitasking

我正在寻找一种分配某些任务的算法。问题如下:

假设我有一个中央任务生产者和一些客户消费者。生产者生成任务并且消费者接受任务(对于初学者,一次一个),处理它们,并且当它们完成时,接受新任务(我已经有任务队列)。

问题是,如果您考虑从生产者到消费者的任务延迟,将任务组合在一起可能是有意义的。例如,假设我们总共有10个任务和2个消费者。如果每个任务需要5毫秒来处理并且网络延迟也是5毫秒,则每个消费者每组发送2组5个任务将花费5毫秒+ 5 * 5毫秒= 30毫秒,而单独发送任务需要5 * 5毫秒+ 5 * 5ms = 50ms,因为每个任务都会出现延迟开销。

它不像分组那么简单,因为某些任务可能需要更长时间,并且将它们分开发送是有意义的,以便让其他消费者并行处理花费更短时间的其他任务。我打算做一些关于任务类型的统计数据。消费者的数量也不是一成不变的。

有什么好的算法或好的阅读可以帮助我实现这个目标吗?

5 个答案:

答案 0 :(得分:1)

当生产者生成任务时,不立即发送任务只会增加该任务的延迟。因此,我假设任务调度程序在当前任务队列的 snapshots 上工作:它接受队列中的所有任务,立即向所有方向发送它们,返回队列,再次取得所有任务在此期间积累的任务,泡沫,冲洗,重复。

调度员维持每个消费者完成时间的估计。它根据增加的完成时间对消费者进行订购,并在最早的完成时间内向消费者的批次添加任务。然后,它将平均任务时间添加到该消费者完成时间估计,从而获得新的估计,然后根据新的估计重新排序消费者(在O(log n)中使用堆)并转到下一个任务。处理完当前快照的所有任务后,将批次发送给消费者并创建新快照。

此政策将平均实现平均消费者负载。它可以改进:

  • 如果每个消费者能够提供关于估计完成时间的一些反馈:它是平均任务时间乘以消费者中待决任务的数量。它更精确,因为消费者将使用已完成任务的实际时间而不是平均值

  • 如果处理每项任务的时间是已知的或可以按任务估算,那么调度员将使用每任务估算值而不是平均值。

编辑:忘记提及:

完成时间估算为start-time + average-task-time * number-of-tasks-sent-to-a-consumer + latency * number-of-batches-sent-to-a-consumer

答案 1 :(得分:1)

为了澄清我对您的问题的评论,我们假设您的消费者中有以下循环:

while (keepConsuming) {
    Task t = Task::get();
    t.process();
}

你可以像这样重写它(假设我们可以使用OpenMP):

Task cur=NULL, next;
do {
    #pragma omp sections
    {
        #pragma omp section
        if (cur != NULL) cur.process();
        #pragma omp section
        next = keepConsuming ? Task::get() : NULL;
    }
    cur = next;
} while (cur != NULL);

这样,while内的process()和get()是并行执行的(显然,假设这两个函数不共享任何状态)。

答案 2 :(得分:1)

啊......细粒度并行性(它提供了更好的负载平衡但是相对更高的同步开销)与粗粒度并行性(显然相反)之间的经典决策。对不起,但没有简单的答案......

一些想法:

  1. 进行大量分析,这是找到合适数量的任务进行分组的好方法。只是好老试错:)

  2. 考虑在每个客户端创建一个本地任务队列。这可以实现某种预取,例如,当任务n完成时,请求任务n + 5并启动任务n + 1。不确定您是否正在使用多线程,或者是否会中断任务n + 1以接受任务n + 5.

  3. 尝试尽可能地压缩任务表示。这可能意味着使用char而不是int(这确实对数组产生了影响)。也许任务的某些部分可以在到达消费者时重新计算。

  4. 考虑在每个消费者身上使用某种计时器作为反馈,以调整下次作为一个群组执行的任务数量。如果你花费太多时间,那么下次就可以减少任务。注意花哨的启发式可能会有一些非常重要的开销。

答案 3 :(得分:0)

似乎简单方法的主要问题是消费者将停止一段时间来获取下一个任务。在摊位期间没有有用的工作。

由于延迟 - 而不是带宽 - 是主要问题,因此一种解决方案是在多个任务中分摊停顿,例如通过将任务分组到批次中。要做到这一点,您需要知道每个任务需要多长时间才能处理。

另一种方法是与处理当前任务并行获取下一个任务。这可以通过两个线程轻松完成:线程A处理当前任务,线程B获取下一个任务。当{1}}完成当前任务时,线程可以切换角色或将下一个任务从A传递到B。这是一种管道并行的形式。

答案 4 :(得分:-1)

如果延迟的定义可以扩展到2维,则意味着消费者可以有不同的延迟,那么您可以尝试空间填充曲线。 sfc细分2d并将复杂度降低到1维度。所以你从f(x,y)计算一个数字。然后,您可以对此数字进行排序,并将此订单中的数字发送给消费者。当然你必须先写一个SFC才能使用它我不会为你做,但如果你有问题我可以帮你。