parallelFor
的以下玩具示例正常(f2
是f1
的并行版本):
// [[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
返回的向量只包含未初始化的值。
非常感谢任何澄清。
答案 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::vec
或std::vector
,当按值传递给工作者时,你真正将一个全新的向量复制到类中,然后填充那个(临时的,复制的)向量 - 所以原始向量实际上从未实际得到了充实。