16

関数を記述し、Rcppでコンパイルしましたinline。今、私はそれを異なるコアで並行して実行したいのですが、奇妙なエラーが発生します。これは最小限の例です。この例では、関数をコンパイルして単独で正常に実行できますが、の関数から呼び出すfunCPP1ことはできません。この関数は単一のプロセスとして適切に実行されますが、並行して実行すると次のエラーが発生します。snowclusterCall

Error in checkForRemoteErrors(lapply(cl, recvResult)) : 
  2 nodes produced errors; first error: NULL value passed as symbol address

そしてここにいくつかのコードがあります:

## Load and compile
library(inline)
library(Rcpp)
library(snow)
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;
'
funCPP1 <- cxxfunction(signature(xbe = "numeric", g="numeric"),body = src1, plugin="Rcpp")

## Single process
A <- matrix(rnorm(400), 20,20)
funCPP1(A, 0.5)

## Parallel
cl <- makeCluster(2, type = "SOCK") 
clusterExport(cl, 'funCPP1') 
clusterCall(cl, funCPP1, A, 0.5)
4

3 に答える 3

19

よく考えてください-インラインは何をしますか?C / C ++関数を作成し、それをコンパイルして動的にロード可能な共有ライブラリにリンクします。あれはどこに座っているの?Rの一時ディレクトリ。

したがって、その共有ライブラリを呼び出すRフロントエンドを他のプロセス(別の一時ディレクトリがあります!!)に転送することで正しいことを試みましたが、そこにdll/soファイルが取得されません。

したがって、ローカルパッケージを作成してインストールし、両方のスノープロセスをロードして呼び出すことをお勧めします。

(そしていつものように:SOよりも多くのRcpp寄稿者によって読まれるrcpp-develリストにもっと質の高い答えがあるかもしれません。)

于 2011-05-20T15:47:35.073 に答える
1

古い質問ですが、上位の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

PSOCKとMPIの両方を使用して、クラスターコンピューティング用の並列パッケージとRhpcパッケージにある多くの機能をまとめたパッケージctools(恥知らずな自己宣伝)を作成しました。上記とほぼ同じ方法で、すべてのノードで「Rcpp::sourceCpp」を呼び出す「c.sourceCpp」という関数がすでにあります。上記を実行する「c.inlineCpp」を追加して、その有用性を確認します。

編集:

Coatlessのコメントに照らして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)
于 2016-09-05T15:45:14.873 に答える
0

各クラスタークラスターノードで、必要なCインライン関数を含むRファイルを調達することで解決しました。

clusterEvalQ(cl, 
    {
     library(inline)
     invisible(source("your_C_func.R"))
    })

また、ファイルyour_C_func.Rには、C関数の定義が含まれている必要があります。

c_func <- cfunction(...)
于 2019-03-22T21:38:34.610 に答える