【问题标题】:Equal loading for parallel task distribution并行任务分配的均等负载
【发布时间】:2017-07-14 06:11:51
【问题描述】:

我有大量的独立任务要运行,我希望将它们分布在一个并行系统上,以便每个处理器执行相同数量的工作,并最大限度地提高我的效率。

我想知道是否有一种通用方法可以找到解决此问题的方法,或者可能只是解决我的确切问题的好方法。

我有 T=150 个要运行的任务,每个任务花费的时间是 t=T。即task1用1个单位时间,task2用2个单位时间……task150用150个单位时间。假设我有 n=12 个处理器,假设开始和清理任务所需的时间可以忽略不计,那么在工作人员之间分配工作负载的最佳方法是什么?

【问题讨论】:

  • 你使用什么语言?
  • 我认为这是装箱问题 不是吗? en.wikipedia.org/wiki/Bin_packing_problem 我想你可能从最长的工作开始,然后逐渐缩短工作,否则你可以完成所有工作,除了一个,结果发现那是最长的。
  • 将任务 1 和 150 分配给处理器 1(它获得 151 个工作时间单位),将任务 2 和 149 分配给处理器 2(它获得 151 个工作时间单位),... 12 个处理器获得其中的 6 个块,剩下 6 个大致相等的任务(任务 73 - 78)要完成。将每个分配给一个处理器。这不是所说的垃圾箱包装问题,或者如果是,它是一个非常容易解决的问题。
  • @HighPerformanceMark 很酷的解决方案!高斯也做了类似的事情……mathcentral.uregina.ca/qq/database/qq.02.06/jo1.html

标签: optimization parallel-processing numbers task processing-efficiency


【解决方案1】:

尽管我最初对 @HighPerformanceMark 的巧妙方法充满热情,但我决定使用 GNU Parallel-j 12 进行实际基准测试,以使用 12 个内核并模拟 1 个工作单元和 1 秒的睡眠时间。

首先,我按照以下建议生成了一份工作列表:

paste <(seq 1 72) <(seq 150 -1 79) 

看起来像这样:

1   150
2   149
3   148
...
...
71  80
72  79

然后我将列表传递给 GNU Parallel 并在最后并行选择剩余的 6 个作业:

paste <(seq 1 72) <(seq 150 -1 79) | parallel -k -j 12  --colsep '\t' 'sleep {1} ; sleep {2}'
sleep 73 &
sleep 74 &
sleep 75 &
sleep 76 &
sleep 77 &
sleep 78 &
wait

运行时间为 16 分 24 秒。


然后我使用了更简单的方法,即首先运行大型作业,这样您就不太可能在最后留下任何大型作业,从而导致 CPU 负载不平衡,因为只需要运行一个大型作业并且其余的 CPU 无关:

time parallel -j 12 sleep {} ::: $(seq 150 -1 1)

运行时间为 15 分 48 秒,因此实际上更快。


我认为另一种方法的问题在于,在前 6 轮 12 对作业之后,剩下 6 个作业,其中最长的需要 78 秒,因此实际上 6 个 CPU 无所事事 78 秒。如果任务数可以被 CPU 数整除,则不会发生这种情况,但 150 不会除以 12。

【讨论】:

    【解决方案2】:

    我得到的解决方案与上面提到的类似。如果有人感兴趣,这是伪代码:

    N_proc = 12.0
    Jobs = range(1,151)
    SerialTime = sum(Jobs)
    AverageTime = SerialTime / N_proc
    
    
    while Jobs remaining:
        for proc in range(0,N_proc):
            if sum(proc) < AverageTime:
               diff = AverageTime - sum(proc)
               proc.append( max( Jobs <= diff ) )
               Jobs.pop( max( Jobs <= diff ) )
            else:
               proc.append( min(Jobs) )
               Jobs.pop( min(Jobs) )
    

    这对我来说似乎是最佳方法。我在许多不同的作业运行时分布上进行了尝试,只要 N_proc

    这是对最大优先的轻微修改,因为每个处理器首先尝试避免做超过其“公平份额”的事情。如果它必须超过它的公平份额,那么它将尝试通过从队列中抓取最小的剩余任务来保持在公平答案附近。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    相关资源
    最近更新 更多