doParallel foreach作用域问题:eval中的错误(expr,envir,enclos):找不到函数

时间:2013-10-29 06:32:49

标签: r timer foreach parallel-processing polling

我想在每个tclTaskSchedule线程中执行doParallel计时器(来自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

确实,使用foreach调用.export = "testfn"会导致同样的错误。

那么出了什么问题?


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

2 个答案:

答案 0 :(得分:1)

我同意Roland的观点,问题在于tclTaskSchedule评估其论点的方式。我的解决方案并不漂亮,但我通过使用testfn导出clusterExport并在foreach循环中将i分配给worker的全局环境来实现它:

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,但这不是必需的。

答案 1 :(得分:0)

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

来自a blog post

  

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)
}

然后可以使用tail -f log.txt终端中的bash来监控此情况。