Невозможно запустить функцию Rcpp в foreach - "Значение NULL, переданное как адрес символа",

Позвольте мне сначала сказать, что я прочитал "Написание R-расширений", виньетка пакета Rcpp и что я создал пакет из Rcpp.package.skeleton().

С момента создания моего пакета я добавил функцию multiGenerateCSVrow(), а затем запустил compileAttributes() в каталоге пакета до установки R CMD build/R CMD. После загрузки моего пакета я могу запустить свою функцию либо напрямую, либо через foreach() с помощью метода %do%.

Когда я пытаюсь запустить параллельно, я получаю сообщение об ошибке:

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"

Здесь пакет NAMESPACE:

# Generated by roxygen2 (4.0.1): do not edit by hand 
useDynLib(myPackage)                                   
exportPattern("^[[:alpha:]]+")                       
importFrom(Rcpp, evalCpp) 

Здесь соответствующий фрагмент RcppExports.cpp:

// multiGenerateCSVrow
SEXP multiGenerateCSVrow(SEXP scoreMatrix, SEXP validMatrix, SEXP cutoffVector, SEXP factorVector, SEXP actualVector, SEXP scaleSample);
RcppExport SEXP myPackage_multiGenerateCSVrow(SEXP scoreMatrixSEXP, SEXP validMatrixSEXP, SEXP cutoffVectorSEXP, SEXP factorVectorSEXP, SEXP actualVectorSEXP, SEXP scaleSampleSEXP) {
BEGIN_RCPP
    SEXP __sexp_result;
    {
        Rcpp::RNGScope __rngScope;
        Rcpp::traits::input_parameter< SEXP >::type scoreMatrix(scoreMatrixSEXP );
        Rcpp::traits::input_parameter< SEXP >::type validMatrix(validMatrixSEXP );
        Rcpp::traits::input_parameter< SEXP >::type cutoffVector(cutoffVectorSEXP );
        Rcpp::traits::input_parameter< SEXP >::type factorVector(factorVectorSEXP );
        Rcpp::traits::input_parameter< SEXP >::type actualVector(actualVectorSEXP );
        Rcpp::traits::input_parameter< SEXP >::type scaleSample(scaleSampleSEXP );
        SEXP __result = multiGenerateCSVrow(scoreMatrix, validMatrix, cutoffVector, factorVector, actualVector, scaleSample);
        PROTECT(__sexp_result = Rcpp::wrap(__result));
    }
    UNPROTECT(1);
    return __sexp_result;
END_RCPP
}

И RcppExports.R:

multiGenerateCSVrow <- function(scoreMatrix, validMatrix, cutoffVector, factorVector, actualVector, scaleSample) {
    .Call('myPackage_multiGenerateCSVrow', PACKAGE = 'myPackage', scoreMatrix, validMatrix, cutoffVector, factorVector, actualVector, scaleSample)
}   

Что он может искать?

Ответы

Ответ 1

У меня была аналогичная проблема, и я решил ее, добавив .noexport = c(<Functions that were implemented in C++>) в foreach.

Я предполагаю, что эти функции импортируются из глобальной среды в параллельные контексты, но поскольку они не являются обычными функциями, они фактически не работают. Это означает, что функции должны загружаться отдельно на каждом node; в моем случае это был вызов SNOW clusterCall(), который использовал различные файлы, включая код на С++.

Ответ 2

У меня также была проблема, что функции, использующие Rcpp, не будут работать внутри foreach. Как предложил Патрик МакКарти, я положил эту функцию в пакет, установил & загрузил пакет и передал его в forearch с .packages = ( "..." ).

У меня все еще есть некоторые ошибки, но это было устранено после обновления всех задействованных пакетов.

(Я бы прокомментировал, но у меня недостаточно репутации, и я думал, что это может быть полезно для некоторых людей)

Ответ 3

Если кто-то еще сталкивается с этой проблемой, кажется, самым легким решением может быть исходный код Cpp в среде кластера.

Как правило, исходный код Cpp исходного кода (в родительской среде) будет выглядеть следующим образом

library(Rcpp)
sourceCpp("code.cpp")

Если вы хотите использовать этот Cpp код параллельно, он также должен быть найден в среде кластера следующим образом

library(Rcpp)
library(parallel)
cl <- makeCluster(detectCores())
clusterEvalQ(cl, { library(Rcpp)
                   sourceRcpp("code.cpp") })
stopCluster(cl)

Теперь код Cpp должен быть доступен для параллельных работников.

Ответ 4

Вдохновленный ответами @henine & @jmb, я попробовал "обратную" опцию, которая заключается в том, что я на самом деле получаю свой R файл с функциями Rccp внутри цикла foreach и обязательно включаю "Rccp" в опцию .packages foreach., Может быть не самым эффективным, но делает работу и просто.

Что-то вроде:

cl = makeCluster(n_cores, outfile="")
registerDoParallel(cl)

foreach(n = 1:N,.packages = "Rcpp",.noexport = "<name of Rccp function>")%dopar%{
  source("Scripts/Rccp_functions.R")
  ### do stuff with functions scripted in Rccp_functions.R
}

stopImplicitCluster()

И, как и в случае с @jmb, я бы прокомментировал, но мне не хватает репутации: D