我在Matlab中运行了很多长时间的模拟,通常需要几分钟到几个小时不等,因此为了加快速度,我决定使用parfor
循环同时运行这些模拟。
arglist = [arg1, arg2, arg3, arg4];
parfor ii = 1:size(arglist, 2)
myfun(arglist(ii));
end
除了一个问题以外,一切都很好:进度打印。由于每个模拟需要很长时间,所以我通常使用类似以下的方式来打印进度:
prevlength = 0;
for ii = 1:tot_iter
% Some calculations here
msg = sprintf('Working on %d of %d, %.2f percent done', ii, tot_iter, ii/tot_iter);
fprintf(repmat('\b', 1, prevlength))
fprintf(msg);
prevlength = numel(msg);
end
但是,如预料的那样,在parfor
循环内这样做会导致混乱。
我在谷歌上搜索了很多以寻找解决方案,并找到了一堆“parfor进度打印机”,例如这个。然而,它们所有的都打印整个parfor
循环的进度,而不是显示每个个别迭代已经进行到哪里。由于parfor
循环中只有大约4-8次迭代,但每次迭代需要大约一个小时,所以这种方法对我来说并不是非常有用。
对我来说理想的解决方案应该是像这样的:
Working on 127 of 10000, 1.27 percent done
Working on 259 of 10000, 2.59 percent done
Working on 3895 of 10000, 38.95 percent done
Working on 1347 of 10000, 13.47 percent done
也就是说,每个模拟运行的情况都会显示在一行中。但我不确定这是否可能,至少我无法想象任何方法来实现这一点。
另一种方法是像这样做:
Sim 1: 1.27% Sim 2: 2.59% Sim 3: 38.95% Sim 4: 13.47%
也就是说,将所有进程都显示在同一行上。为了做到这一点,您需要跟踪每个模拟要写入的行上的位置,并在那里写入,而不删除其他进度。我无法想象这该如何实现,这种做法可行吗?
如果有其他我没有想到的解决我的问题的方法(显示每个单独迭代的进度),我很乐意听听。
由于这是我第一次在SO上提问,很可能有我忽略的问题;如果有的话,请随时在下面评论。
编辑
收到这个答案后,我认为我应该分享一下我如何使用它来解决我的问题,因为我没有像答案中那样完全使用它,以防别人遇到相同的问题。
这是一个小测试程序,基本上与我的程序结构相同,利用了答案中提到的进度条(parfor_progress
):
function parfor_progress_test()
cpus = feature('numCores');
matlabpool('open', cpus);
cleaner = onCleanup(@mycleaner);
args = [1000, 1000, 1000, 1000];
m = sum(args);
parfor_progress(m);
parfor ii = 1:size(args,2)
my_fun(args(ii));
end
parfor_progress(0);
end
function my_fun(N)
for ii = 1:N
pause(rand*0.01);
parfor_progress;
end
end
function mycleaner
matlabpool close;
fclose all;
end
if mod(ii, 100) == 0; disp(' X ');end
。如果我有1000次迭代,如果它已经打印了五个X,则完成了一半——显然这需要一点运气,因为迭代是随机选择的。所以,这是一个完全的hack,但在紧急情况下它确实有效。坦率地说,在实践中,我发现它可以工作,尽管它有明显的缺陷。 - eric