C++ 采样条件分布OpenMP

C++ 采样条件分布OpenMP,c++,c++17,openmp,C++,C++17,Openmp,我有一个函数可以随机抽取样本: Sample sample(); 我有一个检查样本是否有效的函数: bool is_valid(Sample s); 这模拟了条件分布。现在我想要很多有效的样本(大多数样本都无效) 所以我想用openMP并行化这段代码 vector<Sample> valid_samples; while(valid_samples.size() < n) { Sample s = sample(); if(is_valid(s)) {

我有一个函数可以随机抽取样本:

Sample sample();
我有一个检查样本是否有效的函数:

bool is_valid(Sample s);
这模拟了条件分布。现在我想要很多有效的样本(大多数样本都无效)

所以我想用openMP并行化这段代码

vector<Sample> valid_samples;
while(valid_samples.size() < n) {
    Sample s = sample();
    if(is_valid(s)) {
        valid_samples.push_back(s);
    }
}
作为一个随机数发生器。如果我假设我的设备有一个随机性源,那么它是有效的并且线程保存吗?有更好的解决方案吗?

您可以使用OpenMP任务并行。最简单的解决方案是将任务定义为单个样本插入:

vector<Sample> valid_samples(n); // need to be resized to allow access in parallel

void insert_ith(size_t i)
{
  do {
    valid_samples[i] = sample();
  } while (!is_valid(valid_samples[i]));
}

#pragma omp parallel
{
  #pragma omp single
  {
    for (size_t i = 0; i < n; i++) 
    {
      #pragma omp task
      insert_ith(i);
    }
  }
}
向量有效样本(n);//需要调整大小以允许并行访问
无效插入物(尺寸i)
{
做{
有效样本[i]=sample();
}而(!is_valid(valid_samples[i]);
}
#pragma-omp并行
{
#布拉格omp单曲
{
对于(大小i=0;i

请注意,这种单任务单插入映射可能存在性能问题。首先,可能会涉及错误的共享,但更糟糕的是,任务管理有一些开销,这对于非常小的任务可能非常重要。在这种情况下,补救方法很简单——不是每个任务插入一个项目,而是一次插入多个项目,例如100个。通常,一个合适的数字是一种权衡:越低产生的任务越多=开销越大,越高可能导致负载平衡越差。

您需要注意代码中的关键部分,即插入答案向量

类似的东西应该可以工作(因为没有给出函数和类型,所以没有编译)

//在平行段之前创建向量,因为它应该是共享的
向量有效_样本(n);//设置初始大小以避免重新分配
int=0;
#pragma omp并行共享(有效样本数,n,达到计数)
{
虽然(达到_count
请注意,
sample()
isvalid都不在临界区内,因为我假设这些函数比向量插入要昂贵得多,或者接受率非常低


如果不是这样的话,您可以使用独立的局部向量并最终合并,但如果您以某种方式减少同步的数量,例如提供固定的迭代次数(至少在很大程度上是如此)

有效的\u样本。size()
没有同步的读取大小是数据竞争。我知道这一点,但我接受了它,因为在最坏的情况下,它太频繁地运行单个迭代(每个线程),这没有任何影响,因此它在最后的重要部分被检查。对于许多迭代来说,这是循环迭代次数的一个不可忽略的差异,它应该比同步请求节省更多的时间。您接受数据竞争吗?即使它们在程序中导致未定义的行为?@schetefan24 std::vector.size()在许多实现中减去两个指针,因此在重新定位和数据竞争的情况下可能不会增加。UB的意思不是说它将在有限的一组可能结果中进行选择。@schetefan24我们需要生成
n
任务。您可以通过单个线程(如我的情况)或并行执行此操作,但每个线程只需要生成任务的一个子集。在我的情况下,任务很大(不太可能有效),但错误共享似乎是一个问题(示例是std::vector,所以是24字节)。我将其更改为在任务中使用局部变量。基准测试有点困难,因为运行时间取决于随机数生成器的种子。您能否对问题的第二部分发表意见。您将如何设置随机数生成器的种子?为什么
omp parallel
omp single
没有有效地取消?Unlikus阅读了一些有关OpenMP任务的内容。是的,它们正在取消,但仅用于生成任务。然后,所有线程并行地解决任务。@Unlikus对什么发表评论?如何播种?有很多方法,只需搜索谷歌或StackOverflow。例如,您可以将线程编号合并到seed中,或者为不同的线程创建一个种子向量,并通过
std::random\u device
初始化它们。
vector<Sample> valid_samples(n); // need to be resized to allow access in parallel

void insert_ith(size_t i)
{
  do {
    valid_samples[i] = sample();
  } while (!is_valid(valid_samples[i]));
}

#pragma omp parallel
{
  #pragma omp single
  {
    for (size_t i = 0; i < n; i++) 
    {
      #pragma omp task
      insert_ith(i);
    }
  }
}