r语言 - doParallel for each 作用域问题:eval(expr, envir, enclos) 中的错误



我想在每个doParallel线程中执行一个tclTaskSchedule计时器(来自tcltk2包)。但是,以下最小代码

library(doParallel)
n <- detectCores()
cl <- makeCluster(n, outfile="out.log")
registerDoParallel(cl)
testfn <- function() print(paste("hello from", i))
foreach(i=1:n, .packages = c("tcltk", "tcltk2"), .verbose = T) %dopar% {
    tclTaskSchedule(1000, testfn(), id = paste0("task", i), redo = 10)
}
stopCluster(cl)

导致错误(不是在控制台中打印,而是以out.log打印)

Error in eval(expr, envir, enclos) : could not find function "testfn"

但是,从.verbose = T参数中,我可以从控制台看到testfn正在导出:

automatically exporting the following variables from the local environment:
  testfn

实际上,使用 .export = "testfn" 调用 foreach 会导致相同的错误。

那么出了什么问题呢?


我为什么要这样做?最后,我想以固定的时间间隔异步轮询多个数据源,并且每个数据源都有自己特定的轮询间隔)

我同意罗兰的观点,问题在于tclTaskSchedule评估其参数的方式。 我的解决方案并不漂亮,但我通过使用 clusterExport 导出testfn并在 foreach 循环中将i分配给工作线程的全局环境来使其工作:

testfn <- function() print(paste("hello from", i))
clusterExport(cl, "testfn")
foreach(i=1:n, .packages = c("tcltk", "tcltk2"), .verbose = F) %dopar% {
    i <<- i
    tclTaskSchedule(1000, testfn(), id = paste0("task", i), redo = 10)
}

我可能也会把.noexport="testfn"传给foreach,但这不是真的必要。

即使

没有tclTaskSchedule,您也会发现另一个问题: 并行化foreach循环中的print语句不会输出到交互式会话:

来自博客文章:

foreach 的一个问题是,它为循环的每次迭代创建新的 RScript 实例,这会阻止将状态消息记录到控制台输出中。

解决方法是创建输出日志文件:

cat("", file="log.txt")
testfn <- function() cat("hello from", i, "n", file="log.txt", append=TRUE)
foreach(i=1:n, .packages = c("tcltk", "tcltk2"), .verbose = T) %dopar% {
    tclTaskSchedule(1000, testfn(), id = paste0("task", i), redo = 10)
}

然后可以使用bash终端的tail -f log.txt进行监控。

相关内容

最新更新