大家好!
我正在进行分子动力学模拟,并最近开始尝试并行实现。乍一看,一切都很简单:在最耗时的循环前写上#pragma omp parallel for指令即可。但事实证明,这些循环中的函数操作的是数组,或者更准确地说,操作的是属于我的类对象的数组,该类包含有关粒子系统和作用于该系统的函数的所有信息。因此,当我在其中一个最耗时的循环之前添加了那个#pragma指令时,计算时间实际上增加了数倍,尽管我的2核4线程处理器已经完全负载。
为了解决这个问题,我编写了另一个更简单的程序。这个测试程序执行两个相同的循环,一个并行执行,另一个串行执行。测量执行这两个循环所需的时间。结果让我感到惊讶:每当第一个循环以并行方式计算时,其计算时间与串行模式相比会减少(分别为1500毫秒和6000毫秒),但第二个循环的计算时间却急剧增加(在串行模式下为6000毫秒,在并行模式下为15000毫秒)。
我尝试使用private()和firstprivate()子句,但结果仍然相同。在并行区域之前定义和初始化的每个变量不应该自动共享吗?如果在另一个向量vec2上执行第二个循环,则计算时间会恢复正常,但为每次迭代创建一个新向量显然不是一个选项。我也尝试将vec1的实际更新放入#pragma omp critical区域,但效果也不好。添加Shared(vec1)子句也没有帮助。如果您能指出我的错误并展示正确的方法,我将不胜感激。
在代码中放置private(i)是否有必要?
以下是此测试程序:
#include "stdafx.h"
#include <omp.h>
#include <array>
#include <time.h>
#include <vector>
#include <iostream>
#include <Windows.h>
using namespace std;
#define N1 1000
#define N2 4000
#define dim 1000
int main(){
vector<int>res1,res2;
vector<double>vec1(dim),vec2(N1);
clock_t t, tt;
int k=0;
for( k = 0; k<dim; k++){
vec1[k]=1;
}
t = clock();
#pragma omp parallel
{
double temp;
int i,j,k;
#pragma omp for private(i)
for( i = 0; i<N1; i++){
for(j = 0; j<N2; j++){
for( k = 0; k<dim; k++){
temp+= j;
}
}
vec1[i]+=temp;
temp = 0;
}
}
tt = clock();
cout<<tt-t<<endl;
for(int k = 0; k<dim; k++){
vec1[k]=1;
}
t = clock();
for(int g = 0; g<N1; g++){
for(int h = 0; h<N2; h++){
for(int y = 0; y<dim; y++){
vec1[g]+=h;
}
}
}
tt = clock();
cout<<tt-t<<endl;
getchar();
}
感谢您的时间!
附言:我使用Visual Studio 2012,我的处理器是Intel Core i3-2370M。 我的汇编文件分为两部分:
i
设为私有变量,因为你正在使用#pragma omp for
的循环变量会自动被设为私有变量,并且无论如何都在并行部分中定义,因此对于每个线程来说都是私有的。这也适用于j
、k
和temp
。请注意,当你开始添加到temp
时,它是未定义的;你应该将其初始化为零。至于另一个问题——你能确认一下你的意思是,如果你使用多个线程运行并行部分,程序的串行部分运行得更慢吗?如果是这样,那可能是内存亲和性的问题。 - Jonathan Dursi