我在 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"
如果我改变
%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()}
谢谢!
古斯塔沃
最佳答案
错误消息“NULL 值作为符号地址传递”是不寻常的,并不是由于函数没有导出到工作线程。 cFunc
函数在被序列化、发送给工作人员和反序列化后不起作用。当它从保存的工作区加载时,它也不起作用,这会导致相同的错误消息。这并不让我感到惊讶,这可能是 inline
的记录行为。包裹。
正如您所展示的,您可以通过创建 cFunc
来解决该问题。在 worker 身上。要有效地做到这一点,您只需对每个工作人员执行一次。使用 doParallel
来做到这一点后端,我将定义一个工作器初始化函数,并使用 clusterCall
在每个工作器上执行它。功能:
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()
请注意,您必须显式创建 PSOCK 集群对象才能调用
clusterCall
.您的示例在 Linux 上运行的原因是
mclapply
调用 registerDoParallel
时使用函数没有参数,而在 Windows 上创建一个集群对象和 clusterApplyLB
函数被使用。使用 mclapply
时,函数和变量不会序列化并发送给工作人员,所以没有错误。如果
doParallel
就好了包括对初始化 worker 的支持,而无需使用 clusterCall
,但还没有。
关于r - Windows 7 上内联函数的 doParallel 问题(适用于 Linux),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18245193/