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

标签 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"

如果我改变 %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/

相关文章:

c++ - 如果在 C++ 中没有先前声明的情况下定义自由函数,是否会隐式内联?

rust - 什么时候应该在 Rust 中使用内联?

c++ - 关于C++内联函数的几个问题

r - 如何根据 R 中的特定行值对列进行子集化?

r - 列出文件夹中与确切文件名匹配的文件

R Shiny DataTable如何防止包含超链接的列中的行选择/取消选择

c++ - 如果我在 C++ 中使用内联函数,为什么会重新定义“template<class T>”?

xslt - 在 BizTalk 中映射递归结构

R ggplot2 - geom_histogram : levels/color removed in plot due to limiting y-scale

r - 在 r 中创建特定长度和字符的向量