我想要运行大量独立任务,并且我希望将它们分发到并行系统上,以便每个处理器执行相同的工作量,并最大限度地提高效率。
我想知道是否有一个通用的方法来找到这个问题的解决方案,或者可能只是解决我的确切问题。
我想要运行T = 150个任务,每个任务的时间是t = T.也就是说,task1需要1个单位的时间,task2需要2个单位的时间... task150需要150个单位的时间。假设我有n = 12个处理器,假设开始和清理任务所需的时间可以忽略不计,那么划分工人之间工作负荷的最佳方法是什么?
答案 0 :(得分: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。
答案 1 :(得分:1)
我遇到的解决方案与上面提到的解决方案类似。如果有人有兴趣,这是伪代码:
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&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; N_jobs。
这是对最大的第一个的略微修改,因为每个处理器首先试图避免做超过它的公平分享&#34;。如果它必须通过它的公平份额,那么它将尝试通过从队列中抓取最小的剩余任务来保持在公平答案附近。