Использование source() в параллельных циклах foreach

Вот пример игрушки, чтобы проиллюстрировать мою проблему.

library(foreach)
library(doMC)
registerDoMC(cores=2)

foreach(i = 1:2) %dopar%{
  i + 2
}
[[1]]
[1] 3

[[2]]
[1] 4

До сих пор так хорошо...

Но если код i + 2 сохраняется в файле addition.R и что я вызываю этот файл с помощью source(), тогда

> foreach(i = 1:2) %dopar%{
+   source("addition.R")
+ }
Error in { : task 1 failed - "object 'i' not found"

Ответ 1

Я не могу полностью воспроизвести игрушку, но у меня была знакомая проблема, которую я смог решить:

source(file, local = TRUE)

который должен анализировать источник в локальной среде, то есть распознавать i.

Ответ 2

Я, наконец, решил проблему, преобразовывая исходный код ( "дополнение .R" ) в функцию и просто передавая в нее переменные. Я не знаю, почему, но предлагаемые решения на основе source(file, local = TRUE) не работают.

Ответ 3

Комментарий от NiceE и ответ Sosel уже обращаются к этому; при вызове source(file) он по умолчанию имеет значение source(file, local = FALSE), что означает, что код в исходном файле оценивается в глобальной среде ( "пользовательская рабочая область" ), и есть, cf. ?source. Обратите внимание, что в глобальной среде нет переменной i. Решение состоит в том, чтобы убедиться, что файл получен в среде, вызывающей его, т.е. Использовать source(file, local = TRUE).

Решение:

library("foreach")

y <- foreach(i = 1:2) %dopar% {
  i + 2
}
str(y)

doMC::registerDoMC(cores = 2L)
y <- foreach(i = 1:2) %dopar% {
  source("addition.R", local = TRUE)
}
str(y)

Пример той же проблемы с циклом for():

Тот факт, что source() оценивается в глобальной среде, которая отличается от вызывающей среды, где i живет, также может быть проиллюстрирована с использованием регулярного цикла for, запустив цикл for в другой среде, чем глобальная, например, внутри функции или посредством:

local({
  for(i in 1:2) {
    source("addition.R")
  }
})

который дает:

Error in eval(ei, envir) : object 'i' not found

Теперь причина, по которой вышеуказанный foreach(i = 1:2) %dopar% { source("addition.R") } работает с registerDoSEQ() тогда и только тогда, когда вызывается из глобальной среды, заключается в том, что тогда итерация foreach оценивается в вызывающей среде, которая является глобальной средой, которая является окружение, которое использует source(). Однако, если использовать local(foreach(i = 1:2) %dopar% { ... }), это также не соответствует аналогичному выше вызову local(for(i in 1:2) { ... }).

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