我在Rcpp
编写了一个函数,并使用inline
进行编译。现在,我想在不同的内核上并行运行它,但是我遇到了一个奇怪的错误。这是一个最小的示例,其中函数funCPP1
可以编译并自行运行,但snow
的{{1}}函数无法调用。该函数作为单个进程运行良好,但在并行运行时会出现以下错误:
clusterCall
以下是一些代码:
Error in checkForRemoteErrors(lapply(cl, recvResult)) :
2 nodes produced errors; first error: NULL value passed as symbol address
答案 0 :(得分:15)
仔细考虑 - 内联有什么作用?它为您创建一个C / C ++函数,然后编译并将其链接到一个可动态加载的共享库。那个人坐在哪里?在R的临时目录中。
所以你通过将 R前端调用该共享库发送给另一个进程(其中有另一个临时目录!!)来尝试正确的事情,但是那里没有得到dll / so文件。
因此,建议是创建一个本地包,安装它并加载雪进程并调用它。
(和往常一样:rcpp-devel列表中可能有更高质量的答案,Rcpp提供商比SO更多。)
答案 1 :(得分:0)
老问题,但我在查看顶级Rcpp标签时偶然发现了它,所以也许这个答案仍然有用。
我认为,当您编写的代码被完全删除并执行您想要的操作时,Dirk的答案是正确的,但编写一个新的软件包可能会很麻烦。像示例中的代码。您可以做的是导出代码块,导出"帮助"编译源代码并运行帮助程序的函数。这将使CXX功能可用,然后使用另一个辅助函数来调用它。例如:
# Snow must still be installed, but this functionality is now in "parallel" which ships with base r.
library(parallel)
# Keep your source as an object
src1 <- '
Rcpp::NumericMatrix xbem(xbe);
int nrows = xbem.nrow();
Rcpp::NumericVector gv(g);
for (int i = 1; i < nrows; i++) {
xbem(i,_) = xbem(i-1,_) * gv[0] + xbem(i,_);
}
return xbem;
'
# Save the signature
sig <- signature(xbe = "numeric", g="numeric")
# make a function that compiles the source, then assigns the compiled function
# to the global environment
c.inline <- function(name, sig, src){
library(Rcpp)
funCXX <- inline::cxxfunction(sig = sig, body = src, plugin="Rcpp")
assign(name, funCXX, envir=.GlobalEnv)
}
# and the function which retrieves and calls this newly-compiled function
c.namecall <- function(name,...){
funCXX <- get(name)
funCXX(...)
}
# Keep your example matrix
A <- matrix(rnorm(400), 20,20)
# What are we calling the compiled funciton?
fxname <- "TestCXX"
## Parallel
cl <- makeCluster(2, type = "PSOCK")
# Export all the pieces
clusterExport(cl, c("src1","c.inline","A","fxname"))
# Call the compiler function
clusterCall(cl, c.inline, name=fxname, sig=sig, src=src1)
# Notice how the function now named "TestCXX" is available in the environment
# of every node?
clusterCall(cl, ls, envir=.GlobalEnv)
# Call the function through our wrapper
clusterCall(cl, c.namecall, name=fxname, A, 0.5)
# Works with my testing
我已经编写了一个包ctools(无耻的自我推销),它包含了用于集群计算的并行和Rhpc软件包中的许多功能,包括PSOCK和MPI。我已经有一个名为&#34; c.sourceCpp&#34;调用&#34; Rcpp :: sourceCpp&#34;在每个节点上,与上面的方式大致相同。我要添加一个&#34; c.inlineCpp&#34;现在我已经看到了它的用处。
根据Coatless&#39;评论,Rcpp::cppFunction()
实际上否定了c.inline
帮助的必要性,尽管仍然需要c.namecall
。
src2 <- '
NumericMatrix TestCpp(NumericMatrix xbe, int g){
NumericMatrix xbem(xbe);
int nrows = xbem.nrow();
NumericVector gv(g);
for (int i = 1; i < nrows; i++) {
xbem(i,_) = xbem(i-1,_) * gv[0] + xbem(i,_);
}
return xbem;
}
'
clusterCall(cl, Rcpp::cppFunction, code=src2, env=.GlobalEnv)
# Call the function through our wrapper
clusterCall(cl, c.namecall, name="TestCpp", A, 0.5)
答案 2 :(得分:0)
我通过在每个群集群集节点上采购带有所需C内联函数的R文件来解决该问题:
clusterEvalQ(cl,
{
library(inline)
invisible(source("your_C_func.R"))
})
您的文件your_C_func.R应该包含C函数定义:
c_func <- cfunction(...)