目录
方案一:C++函数在R包中
方案二:C++函数在本地,通过Rcpp::sourceCpp("fun_name.cpp")使用
方案三:将C++函数写在当前脚本中
题外话:为什么要研究foreach+Rcpp?
本文参考:
问题:在foreach中使用Rcpp的函数无法工作
相关问题描述链接
cl <- makePSOCKcluster(8)
registerDoParallel(cl)
rows <- foreach(i=1:8,.combine=rbind,.packages="myPackage") %dopar% multiGenerateCSVrow(scoreMatrix=NIsample,
validMatrix = matrix(1,nrow=10,ncol=10),
cutoffVector = rep(0,10),
factorVector = randomsCutPlus1[i,],
actualVector = rep(1,10),
scaleSample = 1)
stopCluster(cl)
~Error in multiGenerateCSVrow(scoreMatrix = NIsample, validMatrix = matrix(1, :
task 1 failed - "NULL value passed as symbol address"中文错误:"NULL值不能当作符号地址用" expression
英文错误:"NULL value passed as symbol address"
如何将foreach和Rcpp结合起来呢?有如下解决方案:
正如Patrick McCarthy所建议的那样,将C++函数放在一个包中,安装并加载了该包,并将其传递给并行运算函数forearch的参数 . packs=("…")
这种方法使用的前提,要将C++函数封装在一个R包中。如果是别人包中的c++函数,可以直接使用这种方式,如果是自己编写的C++函数,这种方式过于复杂,复杂原因在于需要打包成一个R函数,麻烦一些。
不需要将C++函数存放在一个R包中,只需要在foreach函数中添加两行语句即可
注:在ParLapply中使用C++函数,也可以通过上述方式,将上述语句放在parLapply(, fun)函数中的 fun中,相当于让每个结点都可以加载这个C++函数。
其中foreach()函数循环体内的 library(Rcpp) 可以替换成foreach(..., .packs="Rcpp") 。
下面是个例子:
cl = makeCluster(n_cores, outfile="")
registerDoParallel(cl)
foreach(n = 1:N,.packages = "Rcpp",.noexport = "")%dopar%{
source("Scripts/Rccp_functions.R")
### do stuff with functions scripted in Rccp_functions.R
}
stopImplicitCluster()
在foreach函数中添加参数 .noexport = c(
)
可能原因:C++函数从全局环境导入到并行中,但是,由于它们不是普通的函数,它们实际上并不起作用。这确实意味着这些C++函数必须在每个节点上单独加载;在我的例子中,这是一个SNOW clusterCall()调用,它获取了各种文件,包括C++代码。
可参考:
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()
明明parLapply+Rcpp可以使用了,执行并行的时候用parLapply+Rcpp就好。但是,有些时候,循环体中某次循环会坏掉,这种时候希望让程序跳过坏掉的次数,继续执行下去,这样避免了因为某次循环换掉,导致前面运行的都废掉了,花费的时间也白费了。而foreach函数中有一个好的参数 .errorhandling = c("stop", "remove", "pass"), 设置.errorhanding="pass",这样当某次循环因为某些原因坏掉时,程序自动跳过这次循环,然后继续运行,最终返回所有循环的值。
关于foreach函数的介绍可以看:使用foreach函数_饮食有度的元气少女的博客-CSDN博客
r - Can't run Rcpp function in foreach - Stack Overflow