【问题标题】:Why is MATLAB job taking a long time running?为什么 MATLAB 作业需要很长时间才能运行?
【发布时间】:2015-11-12 08:26:23
【问题描述】:

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

示例 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 语句,但它出错了(见结束语 em> 下面)。

我的第二次尝试是关注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 告诉我:

使用“本地”配置文件启动并行池(parpool)...连接到 4 个工作人员。

警告:此作业将一直排队,直到并行池关闭。

MATLAB 终端一直处于等待状态,等待完成。然后我通过Home -> Parallel -> Monitor jobs 打开Jobs Monitor,看到有两个工作,其中一个状态为running。但他们都不会完成。

问题

  • 为什么运行时间太长,因为这是一项非常简单的任务?

  • 在下面并行化我的函数的最佳方法是什么? (“重”部分在分离函数convolveSeries中)

文件 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 给了我一个奇怪的错误:

使用 matlabpool 时出错(第 27 行) matlabpool 已被删除。

要查询已启动的并行池的大小,请查询池的“NumWorkers”属性。

要检查池是否已启动,请使用 'isempty(gcp('nocreate'))'。

parallel_function 中的错误(第 317 行) Nworkers = matlabpool('size');

convContinuous 中的错误(第 18 行) parfor i = 1:n

我的version 命令输出

Parallel Computing Toolbox                            Version 6.6        (R2015a)

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

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

convContinuous 中的错误>makeF%1/F%(第 1 行)

函数 res = convContinuous(tData, sData, smoothFun, par)

在调用“convContinuous>makeF%1/F%”期间未分配输出参数“res”(可能还有其他参数)。

parallel_function 中的错误>iParFun(第 383 行) output.data = processInfo.fun(input.base, input.limit, input.data);

parProcess 中的错误(第 167 行) data = processFunc(processInfo, data);

parallel_function 中的错误(第 358 行) stateInfo = parProcess(@iParFun, @iConsume, @iSupply, ...

convContinuous 中的错误(第 14 行) parfor i = 1:numel(sData(1,:))

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

解决错误

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

一旦我从pathdef.m 中删除pforfun,parfor(convContinuous 函数中的第 18 行)就开始正常工作了。

提前谢谢你!

【问题讨论】:

  • 关于您的最后一个错误:这是完整的错误堆栈吗?它属于哪个代码,我无法在您的代码中找到这些行。
  • 在尝试运行文档中的批处理示例时,我注意到并行池也无限期地持有作业。它只是去某个地方,当你等待(工作)时它只是很忙,直到你强制杀死 matlab。
  • convContinuous&gt;makeF%1/F% 是由parfor 机器制造的函数的名称。拥有可执行的复制步骤以查看问题所在会很有帮助。我不清楚你为什么会看到这个 - 当然你的 convolveSeries 函数无条件地提供了它的输出参数。
  • 感谢您的反馈。然后我发现最后一个错误是由函数parallel_function 生成的,我认为它是一个内置函数。但实际上它是文件交换中名为pforfun 的代码的一部分。我从我的pathdef.m 和parfor 中删除了pforfun 工作!

标签: multithreading matlab parallel-processing


【解决方案1】:

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

如果您删除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&gt;makeF%1/F% (line 1)指的是什么。

【讨论】:

  • 要重现错误,您只需取消注释convContinuous 函数的第18 行,其中声明了parfor,并使用for 语句注释掉它下面的行。但是,由于你们无法重现该问题,因此我去查看是否有本地问题而不是 MATLAB 错误。函数parallel_function 是pforfun 的包装器,我很久以前从File Exchange 下载了它,并将它放在我的pathdef.m 中。我从pathdef.m 中删除了它,parfor 开始正常工作。
【解决方案2】:

感谢这里的人们警惕(说他们无法重现我的错误),我继续寻找错误的根源。我意识到这是一个本地错误,因为我的 pathdef.m 中有 pforfun 其中 I downloaded long ago from File Exchange。

一旦我从我的pathdef.m 中删除pforfun,parfor(convContinuous 函数中的第 18 行)开始正常工作。

【讨论】:

    猜你喜欢
    • 2020-11-08
    • 1970-01-01
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    相关资源
    最近更新 更多