为什么 MATLAB 作业需要很长时间 运行?

Why is MATLAB job taking a long time running?

我有一个函数(卷积),如果它在许多列的矩阵上运行(下面的函数代码),它会变得非常慢。因此我想并行化代码。

示例 MATLAB 代码:

x = zeros(1,100);
x(rand(1,100)>0.8) = 1;
x = x(:);
c = convContinuous(1:100,x,@(t,p)p(1)*exp(-(t-p(2)).*(t-p(2))./(2*p(3).*p(3))),[1,0,3],false)
plot(1:100,x,1:100,c)

如果x是一个包含许多列的矩阵,代码会变得很慢...我的第一次尝试是将for更改为parfor语句,但它出错了(请参阅下面的结论

我的第二次尝试是遵循 this example,它展示了如何在作业中安排任务,然后将作业提交到本地服务器。通过让最后一个参数 isParallel 成为 true.

,我在下面的函数中实现了该示例

示例 MATLAB 代码为:

x = zeros(1,100);
x(rand(1,100)>0.8) = 1;
x = x(:);
c = convContinuous(1:100,x,@(t,p)p(1)*exp(-(t-p(2)).*(t-p(2))./(2*p(3).*p(3))),[1,0,3],true)

现在,MATLAB 告诉我:

Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers.

Warning: This job will remain queued until the Parallel Pool is closed.

并且 MATLAB 终端一直处于等待状态,等待完成。然后,我通过 Home -> Parallel -> Monitor jobs 打开 Jobs Monitor,看到有两个作业,其中一个状态为 running。但是 none 将永远完成。

问题

文件convContinuous.m

function res = convContinuous(tData, sData, smoothFun, par, isParallel)
% performs the convolution of a series of delta with a smooth function of parameters par
% tData = temporal space
% sData = matrix of delta series (each column is a different series that will be convolved with smoothFunc)
% smoothFun = function used to convolve with each column of sData
%             must be of the form smoothFun(t, par)
% par = parameters to smoothing function
    if nargin < 5 || isempty(isParallel)
        isParallel = false;
    end
    if isvector(sData)
        [mm,nn] = size(sData);
        sData = sData(:);
    end
    res = zeros(size(sData));
    [ ~, n ] = size(sData);
    if ~isParallel
        %parfor i = 1:n % uncomment this and comment line below for strange error
        for i = 1:n
            res(:,i) = convolveSeries(tData, sData(:,i), smoothFun, par);
        end
    else
        myPool = gcp; % creates parallel pool if needed
        sched = parcluster; % creates scheduler
        job = createJob(sched);
        task = cell(1,n);
        for i = 1:n
            task{i} = createTask(job, @convolveSeries, 1, {tData, sData(:,i), smoothFun, par});
        end
        submit(job);
        wait(job);
        jobRes = fetchOutputs(job);
        for i = 1:n
            res(:,i) = jobRes{i,1}(:);
        end
        delete(job);
    end
    if isvector(sData)
        res = reshape(res, mm, nn);
    end
end

function r = convolveSeries(tData, s, smoothFun, par)
    r = zeros(size(s));
    tSpk = s == 1;
    j = 1;
    for t = tData
        for tt = tData(tSpk)
            if (tt > t)
                break;
            end
            r(j) = r(j) + smoothFun(t - tt, par);
        end
        j = j + 1;
    end
end

结束语

作为旁注,我无法使用 parfor 来完成它,因为 MATLAB R2015a 给了我一个奇怪的错误:

Error using matlabpool (line 27) matlabpool has been removed.

To query the size of an already started parallel pool, query the 'NumWorkers' property of the pool.

To check if a pool is already started use 'isempty(gcp('nocreate'))'.

Error in parallel_function (line 317) Nworkers = matlabpool('size');

Error in convContinuous (line 18) parfor i = 1:n

我的version命令输出

Parallel Computing Toolbox                            Version 6.6        (R2015a)

与我的 MATLAB 版本兼容。差不多all other tests我做的都OK。然后我不得不认为这是一个 MATLAB 错误。

我尝试将 matlabpool 更改为 gcp,然后通过 parPoolObj.NumWorkers 检索工人数量,在两个不同的内置函数中更改此细节后,我收到另一个错误:

Error in convContinuous>makeF%1/F% (line 1)

function res = convContinuous(tData, sData, smoothFun, par)

Output argument "res" (and maybe others) not assigned during call to "convContinuous>makeF%1/F%".

Error in parallel_function>iParFun (line 383) output.data = processInfo.fun(input.base, input.limit, input.data);

Error in parProcess (line 167) data = processFunc(processInfo, data);

Error in parallel_function (line 358) stateInfo = parProcess(@iParFun, @iConsume, @iSupply, ...

Error in convContinuous (line 14) parfor i = 1:numel(sData(1,:))

我怀疑最后一个错误是因为 parfor 循环中的函数调用需要很多参数,但我真的不知道。

解决错误

感谢这里的人的谨慎评论(说他们无法重现我的错误),我继续寻找错误的来源。我意识到这是一个本地错误,因为我的 pathdef.m 中有 pforfunI downloaded long ago from File Exchange.

pathdef.m 中删除 pforfun 后,parforconvContinuous 函数中的第 18 行)开始运行良好。

提前致谢!

您创建的并行池正在阻止您的作业 运行。当您使用作业和任务 API 时,您不需要(也不能)打开池。当您查看作业监视器时,您看到的 运行 作业是支持并行池的作业,只有在删除池时才会完成。

如果您删除 convContinuous 中表示 myPool = gcp 的行,那么它应该可以工作。作为一种优化,您可以使用向量化形式的 createTask,这比在循环中创建任务更有效,即

inputCell = cell(1, n);
for i = 1:n
    inputCell{i} = {tData, sData(:,i), smoothFun, par};
end
task = createTask(job, @convolveSeries, 1, inputCell);

然而,说了这么多,您应该能够使用 parfor 使这段代码工作。您遇到的第一个错误是由于 matlabpool 被删除,现在已被 parpool 取代。

第二个错误似乎是由您的函数未返回正确输出引起的,但错误消息似乎与您发布的代码不对应,所以我不确定。具体我不知道convContinuous>makeF%1/F% (line 1)指的是什么。

感谢这里的人的谨慎评论(说他们无法重现我的错误),我继续寻找错误的来源。我意识到这是一个本地错误,因为我的 pathdef.m I downloaded long ago from File Exchange.

中有 pforfun

从我的 pathdef.m 中删除 pforfun 后,parforconvContinuous 函数中的第 18 行)开始运行良好。