我试图并行化以下程序,但不知道如何减少数组.我知道不可能这样做,但还有其他选择吗?谢谢.(我添加了对m的减少,这是错误的,但希望就如何做到这一点提出建议.)
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <omp.h>
using namespace std;
int main ()
{
int A [] = {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};
int S [10];
time_t start_time = time(NULL);
#pragma omp parallel for private(m) reduction(+:m)
for (int n=0 ; n<10 ; ++n ){
for (int m=0; m<=n; ++m){
S[n] += A[m];
}
}
time_t end_time = time(NULL);
cout << end_time-start_time;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 亚历山大·斯捷潘诺夫在A9的一篇精彩讲座(强烈推荐,顺便说一句)中指出,关联属性为我们提供了可并行性 - 这些日子是编译器,CPU和程序员自己可以利用的非常有用和重要的特性:
// expressions in parentheses can be done in parallel
// because matrix multiplication is associative
Matrix X = (A * B) * (C * D);
Run Code Online (Sandbox Code Playgroud)
但是,交换性财产给我们带来了什么?重新排序?乱序执行?
math parallel-processing cpu cpu-architecture compiler-optimization
在omp临界区之后是否存在隐含的omp障碍
例如,我可以将以下代码版本-1修改为版本-2.
VERSION-1
int min = 100;
#pragma omp parallel
{
int localmin = min;
#pragma omp for schedule(static)
for(int i = 0; i < 1000; i++)
localmin = std::min(localmin, arr[i]);
#pragma omp critical
{
min = std::min(localmin, min)
}
}
Run Code Online (Sandbox Code Playgroud)
VERSION-2
int min = 100;
#pragma omp parallel
{
int localmin = min;
#pragma omp for schedule(static) nowait
for(int i = 0; i < 1000; i++)
localmin = std::min(localmin, arr[i]);
#pragma omp critical
{
min = std::min(localmin, min)
} …
Run Code Online (Sandbox Code Playgroud) 我想使用OpenMP并行填充直方图.我在C/C++中使用OpenMP提出了两种不同的方法.
第一种方法为每个线程proccess_data_v1
创建一个私有直方图变量hist_private
,并行填充它们,然后将私有直方图加到hist
一个critical
部分中的共享直方图中.
第二种方法生成proccess_data_v2
一个直方图的共享数组,其数组大小等于线程数,并行填充此数组,然后并行地对共享直方图求和hist
.
第二种方法似乎优于我,因为它避免了临界区并且并行地对直方图求和.但是,它需要知道线程数和调用omp_get_thread_num()
.我一般都试图避免这种情况.有没有更好的方法来执行第二种方法而不引用线程数并使用大小等于线程数的共享数组?
void proccess_data_v1(float *data, int *hist, const int n, const int nbins, float max) {
#pragma omp parallel
{
int *hist_private = new int[nbins];
for(int i=0; i<nbins; i++) hist_private[i] = 0;
#pragma omp for nowait
for(int i=0; i<n; i++) {
float x = reconstruct_data(data[i]);
fill_hist(hist_private, nbins, max, x);
}
#pragma omp critical
{
for(int i=0; i<nbins; i++) {
hist[i] += hist_private[i];
}
} …
Run Code Online (Sandbox Code Playgroud) 我正在使用gcc-4.7.4
编译器的源代码.我必须学习OpenMP
图书馆的工作,我已经阅读了不同版本的OpenMP的文档,我没有找到任何关于炒锅机制的信息.是的,OpenMP不支持工作窃取机制吗?
我有一个算法,其中一个目标是填充向量.出于性能考虑,算法的迭代遍布OpenMP线程.我想知道哪种方式可以提供更好/更安全的填充向量的方法.
注意,向量的排序必须是一致的(即vec1的值n必须来自与vec2的值n相同的迭代.)
假设1:
std::vector<BasicType> vec1;
std::vector<BasicType> vec2;
#pragma opm parallel for
for(...)
{
// Do some intensive stuff to compute val1 and val2
// ...
#pragma omp critical
{
vec1.push_back(val1);
vec2.push_back(val2);
}
}
// Then go on to work with vec1 and vec2...
Run Code Online (Sandbox Code Playgroud)
假设2:
std::vector<BasicType> vec1;
std::vector<BasicType> vec2;
#pragma opm parallel
{
std::vector<BasicType> vec1local;
std::vector<BasicType> vec2local;
#pragma omp for
for(...)
{
// Do some intensive stuff to compute val1 and val2
// ...
vec1local.push_back(val1);
vec2local.push_back(val2);
}
#pragma omp critical
{ …
Run Code Online (Sandbox Code Playgroud) 我有以下要并行化的代码:
int ncip( int dim, double R)
{
int i;
int r = (int)floor(R);
if (dim == 1)
{
return 1 + 2*r;
}
int n = ncip(dim-1, R); // last coord 0
#pragma omp parallel for
for(i=1; i<=r; ++i)
{
n += 2*ncip(dim-1, sqrt(R*R - i*i) ); // last coord +- i
}
return n;
}
Run Code Online (Sandbox Code Playgroud)
当我尝试并行化for循环时,没有openmp运行的程序执行时间是6.956s,我的执行时间大于3分钟(这是因为我自己结束了).在并行化此代码方面我做错了什么?
第二次尝试
int ncip( int dim, double R)
{
int i;
int r = (int)floor( R);
if ( dim == 1)
{ return …
Run Code Online (Sandbox Code Playgroud) 我还是很困惑。如果我在 OpenMP 中使用 reduce 子句会发生错误共享吗?(两个代码片段都给出了正确的结果。)
一个小例子,其中需要数组的最大值:
double max_red(double *A, int N){
double mx = std::numeric_limits<double>::min();
#pragma omp parallel for reduction(max:mx)
for(int i=0; i<N; ++i){
if(A[i]>mx) mx = A[i];
}
return mx;
}
Run Code Online (Sandbox Code Playgroud)
这个例子也可以用额外的填充来编写
double max_padd(double *A, int N){
omp_set_num_threads(NUM_THREADS);
double local_max[NUM_THREADS][8];
double res;
#pragma omp parallel
{
int id = omp_get_thread_num();
local_max[id][0] = std::numeric_limits<double>::min();
#pragma omp for
for(int i=0; i<N; ++i){
if(A[i]>local_max[id][0])local_max[id][0]=A[i];
}
#pragma omp single
{
res = local_max[0][0];
for(int i=0; i<NUM_THREADS; ++i){
if(local_max[i][0]> res)res = local_max[i][0];
}
} …
Run Code Online (Sandbox Code Playgroud) 假设我们想在OpenMP循环中计算一些东西.比较减少
int counter = 0;
#pragma omp for reduction( + : counter )
for (...) {
...
counter++;
}
Run Code Online (Sandbox Code Playgroud)
与原子增量
int counter = 0;
#pragma omp for
for (...) {
...
#pragma omp atomic
counter++
}
Run Code Online (Sandbox Code Playgroud)
原子访问立即提供结果,而减少仅在循环结束时假定其正确值.例如,减少不允许这样:
int t = counter;
if (t % 1000 == 0) {
printf ("%dk iterations\n", t/1000);
}
Run Code Online (Sandbox Code Playgroud)
从而提供较少的功能.
为什么我会使用减少而不是原子访问计数器?
我试图了解 OMP 如何处理不同的for
循环声明。我有:
int main()
{
int i, A[10000]={...};
double ave = 0.0;
#pragma omp parallel for reduction(+:ave)
for(i=0;i<10000;i++){
ave += A[i];
}
ave /= 10000;
printf("Average value = %0.4f\n",ave);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
其中{...}
是从 1 到 10000 的数字。此代码打印正确的值。#pragma omp parallel for reduction(+:ave)
如果我使用is#pragma omp parallel for private(ave)
的结果代替。我想我明白什么是,但想知道它是否可以替代以及如何替代。printf
0.0000
reduction(oper:list)
private