导出 RcppParallel::RVector 与 std::vector

问题描述 投票:0回答:1

考虑以下串行示例函数:

// [[Rcpp::plugins(cpp20)]]
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector example_fun(int n) {
  Rcpp::NumericVector result (n);
  for(int i = 0; i < n; ++i) {
    result[i] = something();
  }
  return result;
}

使用 OpenMP 并行化此循环需要使用例如

std::vector
RcppParallel::RVector
,因为 Rcpp 向量不是线程安全的。对应的并行
std::vector
版本是

// [[Rcpp::plugins(cpp20)]]
// [[Rcpp::plugins(openmp)]]
#include <Rcpp.h>
#include <omp.h>
#include <vector>

// [[Rcpp::export]]
std::vector<double> example_fun(int n) {
  std::vector<double> result (n);
  #pragma omp parallel for
  for(int i = 0; i < n; ++i) {
    result[i] = something();
  }
  return result;
}

RcppParallel::RVector<double> example_fun(int n)
类似,用于
RcppParallel::RVector

如果我理解正确的话,导出

Rcpp::NumericVector
可以使数据可供 R 使用,而无需复制它,因为它本质上是 R 的本机数据类型。我想知道的是,导出
std::vector
RcppParallel::RVector
在内部如何工作?向量被复制了吗?是不是感动了?是否需要类型转换?重要的是,这两个选项之一是否明显比另一个更有效?

作为一个快速的附加问题,我还想知道,Rcpp 胎面安全问题是否也适用于矢量化 simd 循环:

#pragma omp simd
#pragma omp parallel for simd

谢谢。

r rcpp rcppparallel
1个回答
0
投票

您可能会让自己的事情变得复杂化。它有助于退后一步,您还可以检查 R 在您玩时所做的事情,例如内存分析选项很好!

简而言之,R 使用

SEXP
类型,并且这些类型具有“原生”整数和双精度向量——您可以从 R 中以
integer(3)
double(4)
的形式访问它们,分别创建和分配三元素向量和四元素向量.

现在,使用

Rcpp::IntegerVector
Rcpp::NumericVector
执行绝对等效的步骤。它使用 R 自己的分配器,并且生成的对象对于 R 来说与在 R 中创建的对象无法区分。(当然,通过 R 本身的 C API 是相同的,Rcpp 访问它。)

另一方面,C++ STL 对象(如

std::vector
)或贡献类型(如
RVector
)使用在别处分配的 内存(这有助于 例如
RcppParallel
,正如您所注意到的,并保持线程安全),因此对于每个其中我们必须将其复制到 R 数据结构中。这确实是它的要点。 “已经像 R 自己的一样”的数据不需要复制。其他一切都需要副本。

(总的来说,你的示例中没有任何地方有 C++20。甚至连 C++11 也没有。你写的东西可能是在十多年前构建的,当时 C++98(!!) 仍然是默认值。生活就是现在在当前的 R 和当前的编译器下好多了,所以我几乎从不设置标准插件,因为如果您使用的是足够当前的系统,C++14 或 C++17 已经是默认值。)

© www.soinside.com 2019 - 2024. All rights reserved.