【问题标题】:functions inside a matlab parfor loopmatlab parfor循环内的函数
【发布时间】:2014-10-03 15:21:18
【问题描述】:

你能在 matlab parfor 循环中使用函数吗?例如我有一个看起来像这样的代码:

matlabpool open 2
Mat=zeros(100,8);
parfor(i=1:100)
    Mat(i,:)=foo();
end

在函数内部,我有一堆其他变量。特别是有一段代码看起来像这样:

function z=foo()
    err=1;
    a=zeros(10000,1);
    p=1;

    while(err>.0001)

        %statements to update err 
        %   .
        %   .
        %   .

        p=p+1;

        %if out of memory allocate more
        if(p>length(a))
            a=[a;zeros(length(a),1)];
        end
    end

    %trim output after while loop
    if(p<length(a))
        a(p+1:end)=[];
    end

    %example output
    z=1:8;

end    

我在某处读到,在嵌套在 matlab parfor 循环内的 for 循环内增长的所有变量都必须预先分配,但在这种情况下,我有一个预先分配的变量,但以后可能会增长。当我使用 mlint 时,matlab 没有给我任何错误,但我想知道是否有我应该注意的问题。

谢谢,

-动作

【问题讨论】:

    标签: matlab parfor matlabpool


    【解决方案1】:

    根据 Mathworks 的 documentation,您对矩阵 Mat 的实现是一个切片变量。这意味着您在不同的迭代中更新同一矩阵的不同“切片”,但迭代不会相互影响。循环之间没有数据依赖性。所以你可以走了。

    在函数foo 内部增长a 不会影响parfor,因为a 是位于foo 堆栈中的常规变量。你可以用a 做任何事情。

    确实存在几个需要注意的问题:

    不要使用 ij 作为迭代计数器

    以任何目的定义ij 都是不好的。

    我从来没有厌倦过向人们推荐这篇文章 - Using i and j as variables in Matlab

    不断增长的a 很糟糕

    每次您执行a=[a;zeros(length(a),1)]; 时,变量都会作为一个整体复制到 RAM 中的一个新的空白位置。由于它的大小每次翻倍,这可能是一场灾难。不难想象。

    一种更轻松的“成长”方式 -

    % initialize a list of pointers
    p = 1;
    cc = 1;
    c{1} = zeros(1000,1);
    % use it
    while (go_on)
        % do something
        disp(c{cc})
        ....
    
        p=p+1;
        if (p>1000)
            cc = cc+1;
            c{cc} = zeros(1000,1);
            p = 1;
        end
    end
    

    在这里,您增长了一个指针列表,一个元胞数组c。它更小、更快,但仍然需要在内存中复制。

    使用最少的内存

    假设你只需要a的一小部分,即a(end-8:end),作为函数输出。 (这个假设基于调用者Mat(i,:)=foo(); where size(Mat, 2)=8。)

    假设erra之前的元素无关,即a(p-1)a(p-2),....(后面我会放松这个假设。)

    您不必将所有以前的结果保存在内存中。如果a用完了,直接扔。

    % if out of memory, don't allocate more; flush it
    if (p>1000)
        p = 1;
        a = zeros(1000,1);
    end
    

    第二个假设可以放宽为您只需要一定数量的先前元素,而这个数字是已知的(希望它很小)。例如,

    % if out of memory, flush it, but keep the last 3 results
    if (p>1000)
        a = [a(end-3:end); zeros(997,1)];
        p = 4;
    end
    

    修剪没那么复杂

    % trim output after while loop
    a(p+1:end)=[];
    

    证明:

    >> a=1:10
    a =
         1     2     3     4     5     6     7     8     9    10
    >> a(3:end)=[]
    a =
         1     2
    >> a=1:10
    a =
         1     2     3     4     5     6     7     8     9    10
    >> a(11:end)=[]
    a =
         1     2     3     4     5     6     7     8     9    10
    >> 
    

    原因是end10(虽然你不能将它用作独立变量),而11:10 给出了一个空数组。

    【讨论】:

    • @rayryeng 谢谢!在您发表评论后又添加了两个部分。
    【解决方案2】:

    简短的回答是肯定的,您可以在 parfor 中调用函数。

    长答案是 parfor 仅在 parfor 内的每次迭代都独立于其他迭代时才有效。当不是这种情况时,Matlab 会进行检查;虽然我不知道它们有多充分的证明。在您的示例中,每个 foo() 调用都可以独立运行并将其返回值存储在 Mat 的特定位置,该位置不会被任何其他 parfor 迭代写入或读取,因此它应该可以工作。

    如果 foo() 正在读取 Mat 中的值,则会出现问题。例如,如果 parfor 同时运行 4 次迭代,并且在每次迭代中, foo() 正在从 Mat(1) 读取,然后根据它读取的内容向 Mat(1) 写入一个新值,读取的时间/writes 会改变输出值,matlab 应该标记它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-10
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多