在并行 foreach 循环中使用 source()

Using source() within parallel foreach loops

这是一个玩具示例来说明我的问题。

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"

我无法完全复制你的玩具,但我有一个类似的问题,我可以通过以下方式解决:

source(file, local = TRUE)

应该在本地环境下解析源,即识别i.

NiceE 的评论和 Sosel 的回答已经解决了这个问题;当调用 source(file) 时,它默认为 source(file, local = FALSE),这意味着源文件中的代码正在全局环境("user's workspace")中进行评估,并且有,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) { ... }) 调用。

结论:没有什么神奇的事情发生,但是理解它有点乏味。

我最终通过将源代码("addition.R") 转换为一个函数并将变量传递给它来解决了这个问题。我不知道为什么,但基于 source(file, local = TRUE) 的建议解决方案不起作用。