我在Windows 7和Linux(SUSE Server 11(x86_64))上都使用R 3.0.1.以下示例代码在Windows上产生错误,但在Linux上不产生错误.列出的所有工具箱在两台机器中都是最新的.Windows错误是:
Error in { : task 1 failed - "NULL value passed as symbol address"
Run Code Online (Sandbox Code Playgroud)
如果我更改%dopar% to %do%
,Windows代码运行没有任何错误.我最初的猜测是,这与Windows中的一些配置问题有关,我尝试重新安装Rcpp和R,但这没有帮助.该错误似乎与作用域有关 - 如果我在f1中定义并编译函数cFunc,那么%dopar%
可以正常工作,但是因为我们为每个任务调用一次编译器,所以它非常慢.
有没有人对错误发生的原因或如何解决它的建议有一些见解?
library(inline)
sigFunc <- signature(x="numeric", size_x="numeric")
code <- ' double tot =0;
for(int k = 0; k < INTEGER(size_x)[0]; k++){
tot += REAL(x)[k];
};
return ScalarReal(tot);
'
cFunc <- cxxfunction(sigFunc, code)
f1 <- function(){
x <- rnorm(100)
a <- cFunc(x=x, size_x=as.integer(length(x)))
return(a)
}
library(foreach)
library(doParallel)
registerDoParallel()
# this produces an error in Windows but not in Linux
res <- foreach(counter=(1:100)) %dopar% {f1()}
# this works for both Windows and Linux
res <- foreach(counter=(1:100)) %do% {f1()}
# The following is not a practical solution, but I can compile cFunc inside f1 and then this works in Windows but it is very slow
f1 <- function(){
library(inline)
sigFunc <- signature(x="numeric", size_x="numeric")
code <- ' double tot =0;
for(int k = 0; k < INTEGER(size_x)[0]; k++){
tot += REAL(x)[k];
};
return ScalarReal(tot);
'
cFunc <- cxxfunction(sigFunc, code)
x <- rnorm(100)
a <- cFunc(x=x, size_x=as.integer(length(x)))
return(a)
}
# this now works in Windows but is very slow
res <- foreach(counter=(1:100)) %dopar% {f1()}
Run Code Online (Sandbox Code Playgroud)
谢谢!古斯塔沃
错误消息"作为符号地址传递的NULL值"是不常见的,并不是由于函数未导出到工作者.该cFunc
函数在序列化,发送给工作者和反序列化后不起作用.当它从已保存的工作空间加载时也不起作用,这会导致相同的错误消息.这并不会让我感到惊讶,它可能是inline
包的记录行为.
如您所示,您可以通过创建工作人员来解决问题cFunc
.为了有效地做到这一点,您只需要对每个工作人员执行一次.要使用doParallel
后端执行此操作,我将定义一个worker初始化函数,并使用该clusterCall
函数在每个worker上执行它:
worker.init <- function() {
library(inline)
sigFunc <- signature(x="numeric", size_x="numeric")
code <- ' double tot =0;
for(int k = 0; k < INTEGER(size_x)[0]; k++){
tot += REAL(x)[k];
};
return ScalarReal(tot);
'
assign('cFunc', cxxfunction(sigFunc, code), .GlobalEnv)
NULL
}
f1 <- function(){
x <- rnorm(100)
a <- cFunc(x=x, size_x=as.integer(length(x)))
return(a)
}
library(foreach)
library(doParallel)
cl <- makePSOCKcluster(3)
clusterCall(cl, worker.init)
registerDoParallel(cl)
res <- foreach(counter=1:100) %dopar% f1()
Run Code Online (Sandbox Code Playgroud)
请注意,必须显式创建PSOCK群集对象才能调用clusterCall
.
您的示例在Linux上运行的原因mclapply
是在registerDoParallel
没有参数的情况下调用时使用该函数,而在Windows上创建集群对象并使用该clusterApplyLB
函数.函数和变量未使用时序列化并发送给worker mclapply
,因此没有错误.
如果doParallel
包括支持初始化工人而不需要使用它会很好clusterCall
,但它还没有.