加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

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

发布时间:2020-12-13 22:34:04 所属栏目:Windows 来源:网络整理
导读:我在 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"
我在 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%更改为%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值”是不常见的,并不是由于函数未导出到worker. cFunc函数在序列化,发送给worker和反序列化后不起作用.当它从已保存的工作空间加载时也不起作用,这会导致相同的错误消息.这并不会让我感到惊讶,它可能是内联包的记录行为.

正如您所演示的那样,您可以通过在worker上创建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()

请注意,必须显式创建PSOCK群集对象才能调用clusterCall.

您的示例在Linux上运行的原因是,在不使用参数调用registerDoParallel时使用mclapply函数,而在Windows上创建集群对象并使用clusterApplyLB函数.使用mclapply时,函数和变量不会被序列化并发送给worker,因此没有错误.

如果doParallel包含对初始化工作者的支持而不需要使用clusterCall会很好,但它还没有.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读