нагрузка не работает с foreach и% dopar% - PullRequest
7 голосов
/ 24 июля 2011

Я столкнулся с некоторыми проблемами при использовании foreach% dopar% при загрузке объектов с диска в память ... Объекты не загружаются при попытке загрузить их при использовании foreach% dopar% (это работает, когда я использую только% do%) Ниже приведен простой пример, который показывает мою проблему.

envir = .GlobalEnv

x <- "X test"
y <- "Y test"
z <- "Z test"

save(x, file="x.RData")
save(y, file="y.RData")
save(z, file="z.RData")

rm(x)
rm(y)
rm(z)

objectsNamesVector <- c("x", "y", "z")

foreach(i=1:length(objectsNamesVector), .combine=function (...) NULL,    .multicombine=TRUE) %do% {
    print(paste("Loading object ", objectsNamesVector[i]," - ", i, " of ",    length(objectsNamesVector), sep=""))
    load(file=paste(objectsNamesVector[i], ".RData", sep=""), envir=envir)
}

print(x)
print(y)
print(z)

rm(x)
rm(y)
rm(z)

foreach(i=1:length(objectsNamesVector), .combine=function (...) NULL, .multicombine=TRUE) %dopar% {
    print(paste("Loading object ", objectsNamesVector[i]," - ", i, " of ", length(objectsNamesVector), sep=""))
    load(file=paste(objectsNamesVector[i], ".RData", sep=""), envir=envir)
}

print(x)
print(y)
print(z)

Результат выполнения этого кода (без ">"):

envir = .GlobalEnv

x <- "X test"
y <- "Y test"
z <- "Z test"

save(x, file="x.RData")
save(y, file="y.RData")
save(z, file="z.RData")

rm(x)
rm(y)
rm(z)

objectsNamesVector <- c("x", "y", "z")

foreach(i=1:length(objectsNamesVector), .combine=function (...) NULL,    .multicombine=TRUE) %do% {
+   print(paste("Loading object ", objectsNamesVector[i]," - ", i, " of ", length(objectsNamesVector), sep=""))
+   load(file=paste(objectsNamesVector[i], ".RData", sep=""), envir=envir)
+ }
[1] "Loading object x - 1 of 3"
[1] "Loading object y - 2 of 3"
[1] "Loading object z - 3 of 3"
NULL

print(x)
[1] "X test"
print(y)
[1] "Y test"
print(z)
[1] "Z test"
rm(x)
rm(y)
rm(z)

foreach(i=1:length(objectsNamesVector), .combine=function (...) NULL, .multicombine=TRUE) %dopar% {
+   print(paste("Loading object ", objectsNamesVector[i]," - ", i, " of ", length(objectsNamesVector), sep=""))
+   load(file=paste(objectsNamesVector[i], ".RData", sep=""), envir=envir)
+ }
NULL

print(x)
Error in print(x) : object 'x' not found
print(y)
Error in print(y) : object 'y' not found
print(z)
Error in print(z) : object 'z' not found

Я понимаю, что не могу улучшить IO с помощью foreach, поскольку IO является последовательным в моей архитектуре. Я просто хотел бы понять, почему это не работает ...

Спасибо за ваш ответ.

С уважением, Samo.

Ответы [ 3 ]

2 голосов
/ 28 июля 2011

Трудно точно сказать, что происходит, не зная:

  1. Какая у вас операционная система.
  2. Какой параллельный бэкэнд вы зарегистрировали для% dopar%

Если вы используете doMC, то код в блоке foreach выполняется внутри процесса fork ().Это означает, что у него есть собственное пространство памяти, и, хотя он будет локально изменять .GlobalEnv, он не будет изменять его в рамках процесса «master».Таким образом, вы заканчиваете тем, что изменяете копию .GlobalEnv.

Если вы выполняете этот код без зарегистрированного бэкэнда, он выполняется «правильно», потому что% dopar% завершается выполнением как% do%.

Одним из способов решения этой ситуации может быть загрузка объектов в новые среды, а затем использование параметра .combine для foreach () для копирования содержимого каждого из них в .GlobalEnv.

2 голосов
/ 26 октября 2013

У меня была та же проблема, когда я пытался использовать «foreach» + «doSnow» для запуска параллельной программы на 32-ядерном компьютере.«foreach» перестал работать и сказал: ОБЪЕКТ НЕ НАЙДЕН!Я использовал «.export» в «foreach», чтобы включить этот внешний объект, но он по-прежнему говорил, что ОБЪЕКТ НЕ НАЙДЕН!Когда я попробовал «doParallel» НЕ «doSnow», это сработало!

external_object <- 1 </p>

library (foreach)
library (doParallel)
registerDoParallel (cores = 32)
getDoParWorkers ()

foreach (i = 1: 32, .combine = c .multicombine = TRUE, .export = c ("external_object"))% dopar% {external_object}

2 голосов
/ 28 июля 2011

Я считаю, что проблема в том, что %do% может записывать в глобальную среду, а %dopar% - нет. Использование %do% очень полезно, если вам нужен синтаксис foreach() и другие полезности, но не требуется параллельный бэкэнд.

Кроме того, поскольку %do% выполняется последовательно, поддержание чистоты глобальной среды может быть оставлено на усмотрение пользователя, поскольку не будет условий гонки. В параллельном случае у вас могут быть условия гонки (то есть некоторые параллельные задачи могут закончиться раньше других и могут привести к случайным, трудно воспроизводимым результатам).

Из-за гоночных условий нецелесообразно иметь прямую запись такого рода операций в глобальную среду, если вы можете избежать этого. Более поздний пользователь может взять такой последовательный код и заменить %do% на %dopar%, надеясь получить более быстрые результаты, но не получить те же результаты. К вашему чести, вы нашли чистый пример того, где это может произойти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...