Функции внутри цикла 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 должен отметить это.