Windows 7上的内联函数的doParallel问题(适用于Linux)

use*_*507 5 r inline

我在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)

谢谢!古斯塔沃

Ste*_*ton 6

错误消息"作为符号地址传递的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,但它还没有.