我正在使用OpenMP编写c ++代码。我有一个全局巨大的数组(100,000多个元素),将通过在for循环中添加值进行修改。有没有办法可以有效地让OpenMP创建的每个线程并行维护其数组的本地副本,然后在循环后加入?由于线程数是一个变量,我无法事先创建数组的本地副本。如果使用全局副本并通过同步锁定解决争用条件,则性能非常糟糕。
谢谢!
编辑: 对不起,不清楚。这里有一些伪代码可以澄清这个场景:
int* huge_array=new int[N];
memset(huge_array, 0, N*sizeof(int));
#pragma omp parallel for
for (i=0; i<n; i++)
{
get a value v independently
get a position p independently
// I have to set a lock here
omp_set_lock(&lock);
huge_array[p] += v;
omp_unset_lock(&lock);
}
有没有办法改善上面代码的性能?
答案 0 :(得分:6)
好的,我终于明白了你想做什么。是的,你使用与ptreads相同的方式。
std::vector<int> A(N,0);
std::vector<int*> local(omp_max_num_threads());
#pragma omp parallel
{
int np = omp_get_num_threads();
std::vector<int> localA(N);
local[omp_get_thread_num()] = localA.data();
// add values to local array
#pragma omp for
for(int i=0; i<num_values; ++i)
localA[position()] += value(); // (1)
// implicit barrier ensures all local copies are ready for aggregation
// aggregate local copies into global array
#pragma omp for
for(int k=0; k<N; ++k)
for(int p=0; p<np; ++p)
A[k] += local[p][k]; // (2)
// implicit barrier ensures no local copy is deleted before aggregation is done
}
但同时进行聚合也很重要。
答案 1 :(得分:1)
在Walter's answer,我相信而不是
std::vector<int*> local(omp_max_num_threads());
应该是
std::vector<int*> local(omp_get_max_threads());
omp_max_num_threads()
不是OpenMP中的例程。
答案 2 :(得分:0)
使用指令
怎么样?'#'pragma omp parallel for private(VARIABLE)
你的程序(只有十字架,而不是这些'')?
编辑: 对于你的代码,我会使用我的指令,锁定和解锁你的变量时你不会花太多时间......
编辑2: 抱歉,如果您在临时存储数据的位置创建临时数组,则无法使用我的代码解决您的问题...
答案 3 :(得分:0)
据我所知,基本上是填充直方图,其中position
是要填充的直方图的bin,而value
是要添加到该bin的权重/值。并行填充直方图相当于进行数组缩减。但是,就我所理解的some version of the Fortran implementation而言,OpenMP的C ++实现没有直接的支持。要使用OpenMP在C ++中进行数组缩减,我有两个建议。
1。)如果直方图(数组)的区间数量远小于填充直方图的值的数量(这通常是首选情况,因为每个区域中需要合理的统计数据),那么你可以并行填充直方图的私有版本,并将它们合并到一个关键部分中。由于箱的数量远小于值的数量,因此这应该是有效的。
2。)但是,如果bin的数量很大(如你的例子所暗示的那样),那么也可以并行合并私有直方图,但这有点棘手。此外,需要注意缓存对齐和错误共享。
我展示了如何执行这两种方法并讨论以下问题中的一些缓存问题: Fill histograms (array reduction) in parallel with openmp without using a critical section