在N
工作人员中连续并行K
令人尴尬的并行工作块的一项常见任务是在伪代码中使用以下算法进行分区:
acc = 0
for _ in range(K):
end = acc + ceil(N/K)
emit acc:end
acc = end
这会发出K
个通常大小为N/K
的连续分区,适用于大型N
。但是,如果K
大约为N
,则可能会导致不平衡,因为最后一名工作人员只能获得很少的项目。如果我们将不平衡定义为分区大小之间的最大绝对差异,那么迭代算法从任何随机分区开始并减少潜在直到最大差异为1(如果K
除N
,则为0)是最佳的。
在我看来,通过执行在线“重新规划”,以下可能是获得相同答案的更有效方式。该算法是否具有名称和最优性证明?
acc = 0
workers = K
while workers > 0:
rem = N - acc
end = acc + ceil(rem/workers)
emit acc:end
acc = end
workers -= 1
修改即可。鉴于我们可以递归地定义上面的循环,我可以看到归纳最优性证明可能有效。在任何情况下,将赞赏其最佳性的名称和确认:)
答案 0 :(得分:1)
划分范围的一种简单方法是:
for i in range(K):
emit (i*N // K):((i+1)*N // K)
这具有可并行化的优点,因为迭代不需要按顺序执行。
很容易证明每个分区都有floor(N/K)
或ceil(N/K)
个元素,很明显每个元素都只在一个分区中。由于地板和天花板相差最多1,因此算法必须是最佳的。
您建议的算法也是最优的(结果相似)。但我不知道它的名字。
划分可以并行完成的范围的另一种方法是使用范围start(N, K, i):start(N, K, i+1)
start(N, K, i)
为(N//K)*i + min(i, N%K)
。 (请注意,N//K
和N%K
只需计算一次。)此算法也是最优的,但会分配不平衡,以便第一个分区是较大的分区。这可能有用也可能没用。
答案 1 :(得分:0)
这是一种更简单的方法。您有floor(N/K)
个任务,可以在工作人员之间进行完美分区,剩下N mod K
个剩余任务。为了保持区域连续,您可以将剩余的任务放在第一个N mod K
工作人员上。
这是势在必行的风格。为了清楚起见,我正在编写任务{0 ..(N-1)},并发出一组连续的任务编号。
offset = 0
for 0 <= i < K:
end = offset + floor(N/K)
if i < N mod K:
end = end + 1
emit {c | offset <= c < end}
offset = end
以更具说明性的风格:
chunk = floor(N/K)
rem = N mod K
// i == worker number
function offset(i) =
i * chunk + (i if i < rem else rem)
for 0 <= i < K:
emit {c | offset(i) <= c < offset(i+1)}
此时,最优性证明非常简单。工作人员i
已分配offset(i+1) - offset(i)
个任务。根据{{1}},这可以是i
或floor(N/K)
任务。