RcppArmadillo和RcppParallel的共存问题

8
以下是关于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 arma::vec 替换 #define vector NumericVector,则这种方法不再有效。代码可以编译和运行,f1 没问题,但是由 f2 返回的向量仅包含未初始化的值。
非常感谢您提前给出的任何澄清。

1
arma::vec 应该成为类的引用成员吗?(对于 Rcpp 的情况来说,这是可行的,因为 R 的向量只是指针上的代理对象,所以您仍然可以访问相同的对象) - Kevin Ushey
2
@KevinUshey 没关系,只需加入两个适当的 & 就可以运行:具体来说,将 vector output; 替换为 vector & output;,并将 mytry(vector out) : output(out) {} 替换为 mytry(vector & out) : output(out) {}。您能否将您的评论作为答案表述?我很乐意接受它。因为我不太可能是唯一遇到这个问题的新手,所以我认为这很值得。 - Elvis
1个回答

9
这里的问题在于,你的类应该通过引用而不是值来获取向量。 这是因为,在使用RcppParallel时,通常需要预先为某个对象分配内存,然后填充该对象——因此并行工作者应该将引用指向你想要填充的对象。 因此,你的工作线程应该像这样(如你所指出的):
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向量时,您将复制指针(而不是底层数据!)以及一些额外的向量位(例如向量的长度) - 因此,“副本”保留对相同数据结构的引用。
当您使用更多“传统”的向量,例如arma :: vec或std :: vector时,将其按值传递给工作者时,实际上是复制整个新向量到类中,然后填充该(临时复制的)向量 - 因此原始向量实际上从未被填充。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接