我有一个相当长时间运行的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
实施中编写得不好的调度程序?如果是这样的话,我该如何构建这个,所以我不会和闲散的工人坐在一起这么久?
答案 0 :(得分:1)
我认为这解释了你在观察的内容。
如果迭代次数多于worker,则一些worker会执行多次循环迭代;在这种情况下,工作人员可能会同时接收多次迭代以减少通信时间。 (来自" When to Use parfor")
在循环结束时,两名工作人员可能会在大约同一时间完成迭代。如果只剩下一组迭代要分配,那么一个工作人员将全部获得它们,另一个工作人员将保持空闲状态。这听起来像是预期的行为,可能是因为底层实现试图降低与工作池相关的通信成本。我浏览了网络和Matlab设置,似乎没有办法调整沟通策略。
答案 1 :(得分:0)
parfor
调度程序尝试对循环进行负载平衡,其中迭代不会花费相同的时间。不幸的是,正如您所观察到的,这可能导致工作人员在循环结束时变得闲置。使用parfor
,您无法控制工作分工;但是你可以使用parfeval
将你的工作分成均匀的块 - 这可能会让你更好地利用。或者,您甚至可以将spmd
与for-drange
循环结合使用。