8

I am trying to create a piece of parallel code to speed up the processing of a very large (couple of hundred million rows) array. In order to parallelise this, I chopped my data into 8 (my number of cores) pieces and tried sending each worker 1 piece. Looking at my RAM usage however, it seems each piece is send to each worker, effectively multiplying my RAM usage by 8. A minimum working example:

A = 1:16;
for ii = 1:8
    data{ii} = A(2*ii-1:2*ii);
end

Now, when I send this data to workers using parfor it seems to send the full cell instead of just the desired piece:

output = cell(1,8);
parfor ii = 1:8
    output{ii} = data{ii};
end

I actually use some function within the parfor loop, but this illustrates the case. Does MATLAB actually send the full cell data to each worker, and if so, how to make it send only the desired piece?

4

3 回答 3

11

根据我的个人经验,我发现 usingparfeval在内存使用方面比parfor. 此外,您的问题似乎更容易破解,因此您可以parfeval用于向 MATLAB 工作人员提交更多较小的作业。

假设workerCnt您有要处理jobCnt工作的 MATLAB 工作人员。让data是一个大小为 的元胞数组,jobCnt x 1它的每个元素对应于对数据进行getOutput分析的函数的数据输入。然后将结果存储在outputsize 的单元格数组中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

此外,如果您想节省更多内存,您可以进一步采用这种方法。您可以做的是,在获取完成作业的结果后,您可以删除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
于 2015-09-04T04:40:52.157 回答
5

@ms 的评论是正确的 - 当对数组进行parfor 切片时,每个工作人员只发送它正在处理的循环迭代所需的切片。parfor但是,您很可能会看到 RAM 使用量的增加超出了您最初的预期,因为不幸的是,当数据通过通信机制从客户端传递给工作人员时,需要数据副本。

如果您只需要工作人员的数据,那么最好的解决方案是尽可能只在工作人员上创建/加载/访问它。听起来您在追求数据并行而不是任务并行,这spmd确实更合适(正如@Kostas 所建议的那样)。

于 2015-08-20T08:17:24.607 回答
3

我建议使用spmdMATLAB 的命令。

您几乎可以像编写非并行实现一样编写代码,并且还可以通过labindex“系统”变量访问当前工作程序。

看看这里:

http://www.mathworks.com/help/distcomp/spmd.html

还有这个关于spmdvs的 SO 问题parfor

SPMD 与 Parfor

于 2015-08-19T13:03:47.073 回答