我尝试在开放式mp中并行化的代码是蒙特卡罗,归结为这样的事情:
int seed = 0;
std::mt19937 rng(seed);
double result = 0.0;
int N = 1000;
#pragma omp parallel for
for(i=0; x < N; i++)
{
result += rng()
}
std::cout << result << std::endl;
我想确保随机数生成器的状态在线程之间共享,并且结果的添加是原子的。
有没有办法用thrust :: omp替换这个代码。从我迄今为止所做的研究来看,看起来像push :: omp更多的是使用多个CPU线程而不是GPU来执行某些标准推力操作的指令。
答案 0 :(得分:2)
是的,可以使用推力来做类似的事情,在主机CPU上使用OMP线程执行(并行)执行推力OMP backend。这是一个例子:
$ cat t535.cpp
#include <random>
#include <iostream>
#include <thrust/system/omp/execution_policy.h>
#include <thrust/system/omp/vector.h>
#include <thrust/reduce.h>
int main(int argc, char *argv[]){
unsigned N = 1;
int seed = 0;
if (argc > 1) N = atoi(argv[1]);
if (argc > 2) seed = atoi(argv[2]);
std::mt19937 rng(seed);
unsigned long result = 0;
thrust::omp::vector<unsigned long> vec(N);
thrust::generate(thrust::omp::par, vec.begin(), vec.end(), rng);
result = thrust::reduce(thrust::omp::par, vec.begin(), vec.end());
std::cout << result << std::endl;
return 0;
}
$ g++ -std=c++11 -O2 -I/usr/local/cuda/include -o t535 t535.cpp -fopenmp -lgomp
$ time ./t535 100000000
214746750809749347
real 0m0.700s
user 0m2.108s
sys 0m0.600s
$
对于这个测试,我使用了带有CUDA 6.5RC的Fedora 20,在4核Xeon CPU上运行(根据time
结果净增加3倍)。可能会对这个特定的代码进行一些进一步的“优化”,但我认为它们会不必要地混淆这个想法,我认为你的实际应用程序比仅仅对随机数进行求和更复杂。
我在这里展示的大部分内容都是从推力直接系统访问页面中提取出来的,但有几种类似的方法可以访问OMP后端,具体取决于您是否希望拥有灵活的,可重定向的代码,或者您想要一个专门使用的代码OMP后端(这个后端专门针对OMP后端)。
推力::减少操作保证了你正在寻找的“原子性”。具体来说,它保证两个线程不会同时尝试更新单个位置。但是,我认为在多线程OMP应用程序中使用std::mt19937
超出了我的答案范围。如果我使用您提供的代码创建一个普通的OMP应用程序,我会观察到(我认为)在多个OMP线程中使用std::mt19937
rng之间的某些交互所导致的结果的可变性。这不是一个可以为你理清的东西。
Thrust也有random number generators,它可以与它一起使用。