Сохраняет ли параллельный foreach в R объекты для дополнительных итераций в рамках одной и той же дочерней операции?

Я запускаю процесс параллельно, используя бэкэнд doParallel / Foreach в R. Я регистрирую набор из 20 ядер как кластер и запускаю процесс примерно 100 раз. Я передаю матрицу каждой итерации параллельных процессов, а в подпроцессе заменяю матрицу случайной выборкой из ее собственных строк. Что мне интересно: следует ли ожидать, что эта модификация сохранится для последующих итераций, обрабатываемых тем же дочерним процессом? Например, когда дочерний процесс 1 завершает свою первую итерацию, начинает ли он вторую итерацию с исходной матрицы или случайной выборки?

Минимальный пример:

   library(doParallel)

   X <- matrix(1:400, ncol=4)

   cl<-makeCluster(2)
   clusterExport(X)
   registerDoParallel(cl)


   results<-foreach(i=1:100) %dopar% {
       set.seed(12345)
       X <- X[sample.int(nrow(X),replace=TRUE),]
       X
   }

РЕДАКТИРОВАТЬ:

Чтобы было ясно, если объект действительно будет сохраняться на протяжении итераций одного и того же рабочего процесса, это не мое желаемое поведение. Скорее, я хочу, чтобы каждая итерация брала новую случайную выборку исходной матрицы, а не случайную выборку самой последней случайной выборки (я понимаю, что в моем минимальном примере она, кроме того, создала бы тот же случайный образец исходной матрицы каждый раз из-за набора семян - в моем реальном приложении я имею дело с этим).


person rsandler    schedule 11.10.2016    source источник


Ответы (1)


Возможны побочные эффекты внутри работника кластера, которые сохраняются во время итераций цикла foreach, но это не поддерживаемая функция foreach. Программы, использующие это преимущество, вероятно, не будут переноситься на другие параллельные серверные части и могут не работать с более новыми версиями программного обеспечения. Фактически, я пытался сделать такой побочный эффект невозможным, когда впервые писал foreach, но в конце концов сдался.

Обратите внимание, что в вашем случае вы не изменяете копию X, которая была явно экспортирована в воркеры: вы изменяете копию, которая была автоматически экспортирована в воркеры с помощью doParallel. Возможно, это вас смутило.

Если вы действительно хотите это сделать, я предлагаю вам отключить автоматический экспорт X, а затем изменить явно экспортированную копию, чтобы программа была четко определена и переносима, хотя и немного некрасива. Вот пример:

library(doParallel)
cl <- makePSOCKcluster(2)
registerDoParallel(cl)
X <- matrix(0, nrow=4, ncol=4)
clusterExport(cl, 'X')
ignore <- clusterApply(cl, seq_along(cl), function(i) ID <<- i)
results <-
  foreach(i=1:4, .noexport='X') %dopar% {
    X[i,] <<- ID
    X
  }
finalresults <- clusterEvalQ(cl, X)

results содержит матрицы после каждой задачи, а finalresults содержит матрицы для каждого из рабочих процессов после завершения цикла foreach.


Обновить

В общем, тело цикла foreach не должно изменять никакую переменную, которая находится за пределами цикла foreach. Я изменяю только те переменные, которые создал ранее на той же итерации цикла foreach. Если вы хотите создать измененную версию, которая будет использоваться только в этой итерации, используйте другое имя переменной.

person Steve Weston    schedule 11.10.2016
comment
Чтобы было ясно, я не хочу, чтобы объект изменялся каждый раз. Скорее, я боялся, что это может происходить без моего ведома, что приведет к ошибкам. Мой вопрос по этому поводу был не очень ясным; Я это исправлю. - person rsandler; 11.10.2016