Adr*_*aan 11 parallel-processing matlab parfor spmd
我正在尝试创建一个并行代码来加速处理非常大(几亿行)的数组.为了与此并行化,我将数据切成8个(我的核心数量)碎片,并尝试将每个工人送到1件.然而,看看我的RAM使用情况,似乎每个工件都发送给每个工作人员,有效地将我的RAM使用量乘以8.最小工作示例:
A = 1:16;
for ii = 1:8
data{ii} = A(2*ii-1:2*ii);
end
Run Code Online (Sandbox Code Playgroud)
现在,当我将这些数据发送给使用parfor
它的工作人员时,它似乎发送了完整的单元格,而不仅仅是所需的部分:
output = cell(1,8);
parfor ii = 1:8
output{ii} = data{ii};
end
Run Code Online (Sandbox Code Playgroud)
我实际上在parfor
循环中使用了一些函数,但这说明了这种情况.MATLAB实际上是将完整的单元格发送data
给每个工作人员,如果是这样,如何让它只发送所需的部分?
mil*_*iez 11
根据我的个人经验,我发现parfeval
在内存使用方面使用比使用更好parfor
.此外,您的问题似乎更容易破解,因此您可以使用parfeval
向MATLAB工作人员提交更小的工作.
假设你有workerCnt
MATLAB工作人员,你将要处理jobCnt
工作.让data
是尺寸的单元阵列jobCnt x 1
,和它的每个元素对应于功能的数据输入getOutput
,其确实的数据进行分析.然后将结果存储在output
大小的单元阵列中jobCnt x 1
.
在以下代码中,作业在第一个for
循环中分配,结果在第二个while
循环中检索.布尔变量doneJobs
指示完成了哪个作业.
poolObj = parpool(workerCnt);
jobCnt = length(data); % number of jobs
output = cell(jobCnt,1);
for jobNo = 1:jobCnt
future(jobNo) = parfeval(poolObj,@getOutput,...
nargout('getOutput'),data{jobNo});
end
doneJobs = false(jobCnt,1);
while ~all(doneJobs)
[idx,result] = fetchnext(future);
output{idx} = result;
doneJobs(idx) = true;
end
Run Code Online (Sandbox Code Playgroud)
此外,如果您想节省更多内存,可以更进一步.您可以做的是,在获取完成作业的结果后,您可以删除相应的成员future
.原因是该对象存储了getOutput
可能会很大的函数的所有输入和输出数据.但是你需要小心,因为删除future
结果索引成员的转移.
以下是我为此porpuse编写的代码.
poolObj = parpool(workerCnt);
jobCnt = length(data); % number of jobs
output = cell(jobCnt,1);
for jobNo = 1:jobCnt
future(jobNo) = parfeval(poolObj,@getOutput,...
nargout('getOutput'),data{jobNo});
end
doneJobs = false(jobCnt,1);
while ~all(doneJobs)
[idx,result] = fetchnext(future);
furure(idx) = []; % remove the done future object
oldIdx = 0;
% find the index offset and correct index accordingly
while oldIdx ~= idx
doneJobsInIdxRange = sum(doneJobs((oldIdx + 1):idx));
oldIdx = idx
idx = idx + doneJobsInIdxRange;
end
output{idx} = result;
doneJobs(idx) = true;
end
Run Code Online (Sandbox Code Playgroud)
来自@ms的注释是正确的 - 当parfor
切片数组时,每个工作程序只发送它正在处理的循环迭代所需的切片.但是,您可能会看到RAM使用量增加超出您最初的预期,因为不幸的是,数据的副本是必需的,因为它是通过parfor
通信机制从客户端传递给工作者的.
如果您只需要工作人员的数据,那么最好的解决方案是尽可能在工作人员上创建/加载/访问它.这听起来像是在追求数据并行性而不是任务并行性,因为这spmd
确实更合适(正如@Kostas建议的那样).