RcppArmadillo和RcppParallel的同居

时间:2014-10-07 10:36:08

标签: rcpp

parallelFor的以下玩具示例正常(f2f1的并行版本):

// [[Rcpp::depends(RcppParallel)]]
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <RcppParallel.h>
#include <iostream>
#define vector NumericVector

using namespace Rcpp;
using namespace RcppParallel;


// compute values i/i+1 for i = 0 to n-1
// [[Rcpp::export]]
vector f1(int n) {
  vector x(n);
  for(int i = 0; i < n; i++) x[i] = (double) i/ (i+1);
  return x;
}

struct mytry : public Worker {
  vector output;

  mytry(vector out) : output(out) {}

  void operator()(std::size_t begin, std::size_t end) {
    for(int i = begin; i < end; i++) output[i] = (double) i/ (i+1);
  }

};

// [[Rcpp::export]]
vector f2(int n) {
  vector x(n);
  mytry A(x);
  parallelFor(0, n, A);
  return x;
}

但是,如果我将#define vector NumericVector替换为#define vector arma::vec,则此功能不再适用。代码编译并运行,f1没问题,但f2返回的向量只包含未初始化的值。

非常感谢任何澄清。

1 个答案:

答案 0 :(得分:7)

这里的问题 - 你的班级应该通过引用而不是值来获取向量。

这是因为,在使用RcppParallel时,您通常会在某处为对象预先分配内存,然后填充该对象 - 因此并行工作者应该引用您要填充的对象。 / p>

所以你的工人应该像你所说的那样:

struct mytry : public Worker {
  vector& output;

  mytry(vector& out) : output(out) {}

  void operator()(std::size_t begin, std::size_t end) {
    for(int i = begin; i < end; i++) output[i] = (double) i/ (i+1);
  }

请注意,这对Rcpp向量起作用(可能令人惊讶),因为它们只是“代理”对象 - 只是封装指向数据的对象。按值传递Rcpp向量时,复制指针(不是基础数据!)加上一些额外的向量位(例如​​向量的长度) - 因此'copy'保留对同一数据结构的引用。 / p>

当您使用更“经典”的矢量时,例如arma::vecstd::vector,当按值传递给工作者时,你真正将一个全新的向量复制到类中,然后填充那个(临时的,复制的)向量 - 所以原始向量实际上从未实际得到了充实。