Вызов функции "mypackage" внутри общественного работника

Я знаю, что у меня проблема с безопасностью потоков. Поскольку код, который я имею сейчас, будет выполняться с 'seThreadOptions(1)'. Мой вопрос в том, что было бы хорошей практикой для преодоления этого.

Я знаю это: Указатель на функцию Threadsafe с Rcpp и RcppParallel через std:: shared_ptr Придет в игру как-нибудь. И я также обдумывал / играл с тем, чтобы сделать внутреннюю функцию частью структуры для параллельного работника. На самом деле, я вызываю две внутренние функции, и я хотел бы, чтобы одна была переменной, а другая - постоянной, и это заставляет меня думать, что мне понадобятся 2 решения.

Ошибка в том, что R сессия, в rstudio, вылетает. Здесь следует обратить внимание на две вещи: 1. если я установил setThreadOptions(1), это будет нормально. 2. если я перенесу 'myfunc' в основной файл cpp и произвожу вызов просто 'myfunc', это тоже будет нормально.

Вот подробный пример:

Первый файл cpp:

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::interfaces(cpp)]]
// [[Rcpp::plugins(cpp11)]]
#include "RcppArmadillo.h"
using namespace arma;
using namespace std;

// [[Rcpp::export]]
double myfunc(arma::vec vec_in){

  int Len = arma::size(vec_in)[0];
  return (vec_in[0] +vec_in[1])/Len;
}

Во-вторых, файл cpp:

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::depends(RcppParallel)]]
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(ParallelExample)]]

#include "RcppArmadillo.h"
#include "RcppParallel.h"
#include "ParallelExample.h"
#include <random>
#include <memory>
#include <math.h>

using namespace Rcpp;
using namespace arma;
using namespace RcppParallel;
using namespace std;

struct PARALLEL_WORKER : public Worker{

  const arma::vec &input;
  arma::vec &output;

  PARALLEL_WORKER(const arma::vec &input, arma::vec &output) : input(input), output(output) {}

  void operator()(std::size_t begin, std::size_t end){


    std::mt19937 engine(1);

    // Create a loop that runs through a selected section of the total Boot_reps
    for( int k = begin; k < end; k ++){
      engine.seed(k);
      arma::vec index = input;
      std::shuffle( index.begin(), index.end(), engine);

      output[k] = ParallelExample::myfunc(index);
  }
}

};

// [[Rcpp::export]]
arma::vec Parallelfunc(int Len_in){

  arma::vec input = arma::regspace(0, 500);
  arma::vec output(Len_in);

  PARALLEL_WORKER  parallel_woker(input, output);
  parallelFor( 0, Len_in, parallel_woker);
  return output;
}

Makevars, как я использую Macintosh:

CXX_STD = CXX11

PKG_CXXFLAGS +=  -I../inst/include

И Пространство имен:

exportPattern("^[[:alpha:]]+")
importFrom(Rcpp, evalCpp)
importFrom(RcppParallel,RcppParallelLibs)
useDynLib(ParallelExample, .registration = TRUE)

export(Parallelfunc)

2 ответа

Решение

Когда вы звоните ParallelExample::myfuncВы вызываете функцию, определенную в inst/include/ParallelExample_RcppExport.h, который использует R API. Это то, что нельзя делать в параллельном контексте. Я вижу две возможности:

  1. Перерабатывать myfunc только для заголовка и включить его в int/include/ParallelExample.h,
  2. Если второй файл cpp находится в том же пакете, поместите подходящее объявление для myfunc в src/first.h, включите этот файл в оба src/first.cpp а также src/second.cppи позвоните myfunc вместо ParallelExample::myfunc, В конце концов, нет необходимости регистрировать функцию в R, если вы хотите вызывать ее только в том же пакете. Регистрация с помощью R предназначена для функций, которые вызываются извне.

В некотором смысле это своего рода побеждает назначение встроенного интерфейса cpp в Rcpp.

Во-первых, cpp сохранен как "ExampleInternal.h":

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::plugins(cpp11)]]
#include "RcppArmadillo.h"
using namespace arma;
using namespace std;

namespace ExampleInternal
{

  double myfunc3(arma::vec vec_in){

    int Len = arma::size(vec_in)[0];
    return (vec_in[0] +vec_in[1])/Len;
  }


}

и второе:

#include "ParallelExample.h"
#include "ExampleInternal.h"
#include <random>
#include <memory>
#include <math.h>

using namespace Rcpp;
using namespace arma;
using namespace RcppParallel;
using namespace ExampleInternal;
using namespace std;

struct PARALLEL_WORKER : public Worker{

  const arma::vec &input;
  arma::vec &output;

  PARALLEL_WORKER(const arma::vec &input, arma::vec &output) : input(input), output(output) {}

  void operator()(std::size_t begin, std::size_t end){


    std::mt19937 engine(1);

    // Create a loop that runs through a selected section of the total Boot_reps
    for( int k = begin; k < end; k ++){
      engine.seed(k);
      arma::vec index = input;
      std::shuffle( index.begin(), index.end(), engine);

      output[k] = ExampleInternal::myfunc3(index);
  }
}

};

// [[Rcpp::export]]
arma::vec Parallelfunc(int Len_in){

  arma::vec input = arma::regspace(0, 500);
  arma::vec output(Len_in);

  PARALLEL_WORKER  parallel_woker(input, output);
  parallelFor( 0, Len_in, parallel_woker);
  return output;
}
Другие вопросы по тегам