Функции внутри цикла Matlab Parfor

Можете ли вы использовать функции внутри цикла 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    

Я где-то читал, что все переменные, которые растут внутри цикла for, вложенного в цикл matlab parfor, должны быть предварительно выделены, но в этом случае у меня есть переменная, которая предварительно выделена, но может вырасти позже. Matlab не дал мне никаких ошибок, когда я использовал mlint, но мне было интересно, если есть проблемы, о которых я должен знать.

Спасибо,

-akt

2 ответа

Согласно документации Mathworks, ваша реализация матрицы Mat является нарезанной переменной. Это означает, что вы обновляете разные "кусочки" одной и той же матрицы на разных итерациях, но итерации не влияют друг на друга. Между циклами нет зависимости от данных. Так что ты в порядке.

рост a внутренняя функция foo не влияет на parfor, так как a регулярная переменная, расположенная в fooстек Вы можете сделать что-нибудь с a,

Существует несколько проблем, на которые стоит обратить внимание:

Не использовать i а также j в качестве счетчиков итераций

определяющий i или же j в любой цели это плохо.

Мне никогда не было скучно посылать людей на этот пост - Использование i и j в качестве переменных в Matlab.

рост a плохо

Каждый раз, когда вы делаете a=[a;zeros(length(a),1)]; переменная целиком копируется в новое пустое место в оперативной памяти. Поскольку его размер удваивается каждый раз, это может быть катастрофой. Не трудно представить.

Более легкий способ "расти" -

% 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(); где size(Mat, 2)=8,)

предполагать err не имеет отношения к предыдущим элементам a, то есть, 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
>> 

Причина в end является 10 (хотя вы не можете использовать его как переменную stanalone), и 11:10 дает пустой массив.

Короткий ответ - да, вы можете вызывать функцию внутри parfor.

Длинный ответ заключается в том, что parfor работает, только если каждая итерация внутри parfor не зависит от других итераций. Matlab проверяет, когда это не так; хотя я не знаю, насколько они полны доказательства. В вашем примере каждый вызов foo() может выполняться независимо и сохранять возвращаемое значение в определенном месте Mat, которое не будет записано или прочитано никакими другими итерациями, поэтому оно должно работать.

Это ломается, если значения в Mat читаются функцией foo(). Например, если parfor выполнял 4 итерации одновременно и внутри каждой итерации, foo() считывал из Mat(1) и затем записывал новое значение в Mat(1), которое было основано на том, что он читал, время чтения /write изменил бы выходные значения, и matlab должен отметить это.

Другие вопросы по тегам