高性能计算之OpenMP——超算习堂学习2 OpenMP学习2——超算习堂一、for指令的使用方法细嚼1.1、parallel for指令的用法在OpenMP并行程序设计中for循环是一种独立的并行指令。它非常重要它的指令格式是#includeomp.h#pragmaomp parallelforfor(ibegin;iend;i){// Content}十分需要注意的是parallel for指令的后面必须要紧跟for语句块并且for循环并行必须要处在parallel并行区块内否则会当作串行执行1.2、parallel for指令的执行机制此前一篇博客已经说明了OpenMP的并行计算模式是插入并行语句的方法如上图。当我们的串行程序执行到并行语句块的时候会从主线程中派生出线程组然后线程组对计算任务进行均分然后并行计算。并行计算结束后重新回到串行程序。1.3、parallel for并行程序设计案例案例1计算两个向量的点乘#includeomp.h#includecstdio#includecstdlib#includecmath#includectimeconstintmaxn5e7;constintmod10000;intvec1[maxn],vec2[maxn],vec[maxn],i;intmain(){srand((unsignedint)time(NULL));for(i0;imaxn;i){vec1[i]rand()%mod;vec2[i]rand()%mod;}printf(--------------before parallel compute---------------\n);clock_t s,t;sclock();for(i0;imaxn;i){vec[i]vec1[i]*vec2[i];}tclock();printf(--------------used time %d ms---------------\n,t-s);sclock();printf(--------------enter parallel compute---------------\n);#pragmaomp parallelnum_threads(20)shared(vec1,vec2,vec)private(i){#pragmaompforfor(i0;imaxn;i){vec[i]vec1[i]*vec2[i];}}tclock();printf(--------------used time %d ms---------------\n,t-s);return0;}计算效率对比案例2parallel for并行计算矩阵乘法#includeomp.h#includecstdio#includecstdlib#includecmath#includectimeconstintmaxn1000;constintmod10000;intvec1[maxn][maxn],vec2[maxn][maxn],vec[maxn][maxn],i,j,k;intmain(){srand((unsignedint)time(NULL));for(i0;imaxn;i){for(j0;jmaxn;j){vec1[i][j]rand()%mod;vec2[i][j]rand()%mod;}}printf(--------------before parallel compute---------------\n);clock_t s1,t1,s2,t2;s1clock();for(i0;imaxn;i){for(j0;jmaxn;j){for(k0;kmaxn;k){vec[i][j](vec1[i][k]*vec2[k][j]);}}}t1clock();printf(----------------used time %d ms-----------------\n,t1-s1);printf(--------------enter parallel compute---------------\n);s2clock();#pragmaomp parallelforcollapse(2)schedule(dynamic)private(i,j,k)shared(vec1,vec2,vec)for(i0;imaxn;i){for(j0;jmaxn;j){for(k0;kmaxn;k){vec[i][j](vec1[i][k]*vec2[k][j]);}}}t2clock();printf(----------------used time %d ms-----------------\n,t2-s2);printf(\n----------------the speedup ratio %lf---------------\n,1.0*(t1-s1)/(t2-s2));return0;}运行结果如下1.4、运用omp parallel for的一些注意事项第一omp parallel for 和 omp for 不要混用一旦在前面有使用过#pragmaomp parallel...语句并且当前还处在这个并行区然后这个时候你想使用for循环并行则千万不要再搞一次#pragmaomp parallelfor这样的操作了因为这样会让线程组重组然后相当于有两重并行举个例子看看在有#pragma omp parallel 的并行区下运行#includeomp.h#includeiostreamusingnamespacestd;intmain(){#pragmaomp parallelnum_threads(10){#pragmaompforfor(inti0;i5;i){#pragmaomp critical{couti iendl;}}}return0;}此时的运行结果是然后如果你多此一举多搞一遍parallel命令就会#includeomp.h#includeiostreamusingnamespacestd;intmain(){#pragmaomp parallelnum_threads(4){#pragmaomp parallelfor// 注意看这里哦for(inti0;i5;i){#pragmaomp critical{couti iendl;}}}return0;}看看这样的“多此一举”的运行结果我们会发现这个0 ~ 4 被重复执行啦这样会影响并行程序结果还会误以为运行的开销变大哦造成这种结果的原因就是parallel命令会告诉操作系统此时我要重组线程组要重新开始并行程序运行。然后这下好啦每个线程到了那句指令的时候都重组线程组白白多执行4次取决于线程数二、多线程下数据访问同步2.1、同步一词在并行计算的含义其实同步啊在并行计算里有两种含义第一线程/进程的运行有的快有的慢我想要在某处各个线程/进程达到同样的状态这叫并行程序的运行同步第二对于共享内存的模型我们需要控制数据的访问达到线程同步。这样做的目的是为了防止多个进程/线程同时访问某个数据、内存导致该数据同时改变这样的作用下会让数据失真举个例子初始有变量a 2,比如线程A要让a,线程B要让a*2。如果不控制访问让变量a或者某语句块的执行的时候只能让一个线程进入执行其他线程等待执行。则会让资源出现同步问题。这就叫数据同步。2.2用critical创建临界区的方式避免线程同步危害#includeomp.h#includeiostreamusingnamespacestd;intmain(){inti,len,cnt0;#pragmaomp parallelnum_threads(6){lenomp_get_num_threads();#pragmaompforprivate(i)for(i0;ilen;i){#pragmaomp critical{coutCurrent is iendl;cnti;}}}coutcnt cntendl;return0;}利用critical指令完成线程同步的运行结果