为什么 Matlab parfor 调度程序让工作人员闲置?

Why is the Matlab parfor scheduler leaving workers idle?

我有一个相当长的 运行 parfor 循环(假设 100,000 次迭代,每次迭代大约需要一分钟),我是 运行 36 核。我注意到,在工作接近尾声时,大量内核闲置,而少数内核完成了我认为每个工作人员必须进行多次迭代的工作。这导致大量的计算时间浪费在等待一名工人完成几项工作,而其他工人却闲着。

以下脚本显示了该问题(使用文件交换实用程序 Par.m):

% Set up parallel pool
nLoop = 480;
p1 = gcp;

% Run a loop 
pclock = Par(nLoop);
parfor iLoop = 1:nLoop
  Par.tic;
  pause(0.1);
  pclock(iLoop) = Par.toc;  
end
stop(pclock);
plot(pclock);

% Process the timing info: 
runs = [[pclock.Worker]' [pclock.ItStart]' [pclock.ItStop]'];
nRuns = arrayfun(@(x) sum(runs(:,1) == x), 1:max(runs));
starts = nan(max(nRuns), p1.NumWorkers);
ends = nan(max(nRuns), p1.NumWorkers);
for iS = 1:p1.NumWorkers
  starts(1:nRuns(iS), iS) = sort(runs(runs(:, 1) == iS, 2));
  ends(1:nRuns(iS), iS) = sort(runs(runs(:, 1) == iS, 3));
end

firstWorkerStops = min(max(ends));
badRuns = starts > firstWorkerStops;
nBadRuns = sum(sum(badRuns)) - (p1.NumWorkers-1);

fprintf('At least %d (%3.1f%%) iterations run inefficiently.\n', ...
  nBadRuns, nBadRuns/nLoop * 100);

按照我的看法,每个工作人员都应该忙到队列为空,之后所有工作人员都闲着。但在这里看起来这并没有发生——在 480 次迭代中,我得到了 6-20 次迭代,这些迭代是在另一个工作人员闲置 一个完整周期 之后从一个工作人员开始的。这个数字似乎与接近总数 2% 的循环迭代次数成线性比例。通过有限的测试,这似乎在 Matlab 2016b 和 2014b 中是一致的。

是否有任何理由表明这是预期的行为,或者这只是 parfor 实现中的一个写得不好的调度程序?如果是这样,我该如何构建它,这样我就不会和闲置的工人坐在一起这么久?

我认为这可以解释您所观察到的情况。

If there are more iterations than workers, some workers perform more than one loop iteration; in this case, a worker might receive multiple iterations at once to reduce communication time. (From "When to Use parfor")

在一个循环即将结束时,两个工作人员可能会同时完成他们的迭代。如果只剩下一组迭代要分配,那么一个工作人员将获得所有迭代,而另一个将保持空闲状态。这听起来像是预期的行为,这可能是因为底层实现试图减少与工作池相关的通信成本。我查看了网络和 Matlab 设置,似乎没有办法调整通信策略。

parfor 调度程序尝试 load-balance for 循环,其中迭代不会花费统一的时间量。不幸的是,正如您所观察到的,这可能导致工作人员在循环结束时变得闲置。使用parfor,您无法控制分工;但您可以使用 parfeval 将您的工作分成均匀的块 - 这可能会给您更好的利用率。或者,您甚至可以将 spmdfor-drange 循环结合使用。