глобалы и парфор

Внутри цикла parfor я пытаюсь вызвать функцию, которая обращается к global, но безрезультатно.

Функция

function a = getA()
   global OPTIONS;
   a=OPTIONS.PROBLEM.A;
end

Петля:

parfor i=1:3
    b=getA();
end

Ошибка:

Error using parallel_function (line 589)

Attempt to reference field of non-structure array.

Что я делаю неправильно?


person olamundo    schedule 30.08.2012    source источник
comment
Я предлагаю быстрое исправление, не переписывая весь ваш код в этом ответе: stackoverflow.com/a/53653710/4262057   -  person JohnAndrews    schedule 06.12.2018


Ответы (2)


Из документации на parfor:

Тело цикла parfor не может содержать объявления глобальных или постоянных переменных.

В контексте вашей проблемы, то есть при вызове функции в parfor, которая, в свою очередь, ссылается на global, это означает: «parfor, вероятно, не даст ожидаемых или значимых результатов».

В этом есть смысл. Рассмотрим следующие

Lab 1:         Lab 2: 

GetB();        GetB();

если содержимое GetB() такое:

function GetB()
    global B;

    %# do something useful

    B = rand;

 end

какое значение будет у B, когда на него будет сделана ссылка на Lab 1? а на Lab 2? Как сообщаются о различных результатах rand? Будет беспорядок!

Написание кода, подходящего для parfor циклов, может быть настоящей проблемой, когда этот код исходит из чего-то, что имеет в виду только обычные for-циклы. Как правило, если вы заранее знаете, что собираетесь написать фрагмент кода Matlab с интенсивными вычислениями, с самого начала записывайте все функции и циклы как parfor циклы. Это единственный способ, при котором такие ошибки не будут стоить вам дня на перекодировку ваших функций.

Преобразование из for в parfor совсем не тривиально.

person Rody Oldenhuis    schedule 30.08.2012
comment
Да, я тоже это видел, но это немного двусмысленно: означает ли это, что я даже не могу ссылаться на существующие глобальные переменные? Объявление внутри getA () - это ссылка на существующую глобальную переменную, а не на создание новой. И есть ли способ побороть это? - person olamundo; 30.08.2012
comment
@noam см. последнее изменение. Самый простой способ исправить это - отключить global от глобального и передать его в качестве аргумента всем функциям, которые в нем нуждаются. - person Rody Oldenhuis; 30.08.2012
comment
@noam ОК, последнее изменение; немного предыстории. Надеюсь это поможет. - person Rody Oldenhuis; 30.08.2012
comment
Категорически не тот случай, когда вызов функции в PARFOR, которая обращается к global данным, является незаконным. Однако, как вы указываете, результаты, скорее всего, будут неожиданными, поскольку различные глобальные переменные не связаны между собой. - person Edric; 30.08.2012
comment
@Edric, ты прав, незаконно - это неправда. Однако все глобальные переменные теряют свою глобальность. - person Rody Oldenhuis; 30.08.2012
comment
Хорошо работает MATLAB 7.11.0 в Linux, переменные global, похоже, существуют (т.е. exist('x','var') возвращает true), но могут не получить оценку, когда вы впоследствии запрашиваете значение (например, tmp=x - ›Undefined function or variable 'x'). Это может зависеть от того, в каком потоке вы находитесь. Лично я считаю, что это плохое поведение со стороны MATLAB ... - person Sanjay Manohar; 21.08.2014
comment
Говоря о бессмысленных / неожиданных результатах: stackoverflow.com/a/49688601/5211833 - person Adriaan; 21.11.2018

GLOBAL данные трудно использовать внутри PARFOR, потому что каждый рабочий процесс является отдельным процессом MATLAB, а глобальные переменные не синхронизируются от клиента (или любого другого процесса) с рабочими. Это сработает, если вы инициализируете глобальные данные из отдельной функции на воркерах. (Как указывает Роди, использование ключевого слова global непосредственно в теле цикла PARFOR не допускается, однако отдельные функции могут это делать). Итак, было бы законно сделать это:

parfor ii=1:matlabpool('size')
  myFcnWhichSetsUpGlobalData(); %# defines global OPTIONS
end
parfor ii=1:N
  result(ii) = myFcnWhichUsesGlobalData(); %# reads global OPTIONS
end

Я бы лично попытался удалить GLOBAL данные из вашего приложения - это улучшит его работу с PARFOR и сделает зависимости более понятными.

Еще один вариант для изучения - моя Worker Object Wrapper, разработанная чтобы вам не приходилось передавать данные рабочим несколько раз. Вы можете использовать это так:

options = buildOptions();
w_options = WorkerObjWrapper(options);
parfor ii=1:N
  result(ii) = myFcnNeedingOptions(ii, w_options.Value);
end
person Edric    schedule 30.08.2012
comment
сохранятся ли глобальные переменные для отдельных рабочих процессов после выхода управления из цикла for, содержащего myFcnWhichSetsUpGlobalData() функцию ИЛИ управление выходит из файла, содержащего myFcnWhichSetsUpGlobalData()? - person Abhinav; 30.10.2017
comment
Да, глобальные переменные в рабочих процессах продолжают работать в обычном режиме, но они не обращают внимания на изменения, внесенные в другие рабочие процессы. (То же самое и с постоянными переменными). - person Edric; 30.10.2017
comment
Так когда же эти переменные Glo-Cal действительно перестают существовать? Когда main() умрет? Кроме того, есть ли в настоящее время способ получить доступ к значениям переменных, локальных для рабочего / процессора, из клиентской программы? - person Abhinav; 31.10.2017