2013-10-29 26 views
0

我想在每个doParallel线程中执行tclTaskSchedule计时器(来自tcltk2包)。但是,下面的最小代码doParallel foreach作用域问题:eval(expr,envir,enclos)中的错误:找不到函数

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在固定的时间间隔多个数据源的异步,并且每个数据源都有自己特定的轮询间隔)

+0

我认为这个问题并不是'dopar',而是'tclTask​​Schedule',它在环境中做了一些内在的魔法。如果你在'foreach'循环中只放入'print(testfn)',你会发现这个函数是在worker上定义的。但是,不知何故'tclTask​​Schedule'在错误的环境中寻找它。我尝试了一些东西,但找不到解决这个问题的方法。 PS:如果你没有并行化运行循环,你会发现你也有懒惰评估的问题。 – Roland

+0

尝试加载'tcltk'。 – Roland

回答

1

我同意Roland的说法,即tclTaskSchedule评估其论点。我的解决方案是不是很漂亮,但我把它用clusterExport出口testfn和分配i的工人在foreach循环中的全球环境中工作:

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,但它不是没有必要。

0

你也将发现另一个问题,即使没有tclTaskScheduleprint报表内的并行foreach循环不会输出到一个交互式会话:

a blog post

foreach的一个问题是它为循环的每次迭代创建新的RScript实例,从而阻止将状态消息记录到c鞋垫输出。

甲解决办法是创建一个输出日志文件:

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.txtbash终端进行监控。

+0

由于代码使用'outfile =“log.txt”',打印语句的输出不需要修改'testfn'就可以到log.txt。它还捕获确定问题原因的关键错误消息。 –

+1

请注意,foreach _does not_为循环的每次迭代创建一个新的Rscript实例:这通常会非常低效。通过doParallel和doSNOW,您可以通过调用makeCluster来创建Rscript实例,这些“工作人员”将重复执行来自可能很多foreach循环的任务。 –

相关问题