Openmp 多线程并行计算。为什么结果每次run出来不一样?

janeyxm 2008-10-09 12:10:32
各位,我遇到下面这样一个问题,困扰很久没有解决。不知哪位可以慷慨赐教?
我用了两个线程把计算任务分为相互独立的两个部分。分别完成之后把结果合并成为完整的结果。但两个部分内部的语句,如 do while...end do中的语句不是相互独立的,即有上下关联。
结果是,如果我计算简单的问题,最终得到正确结果,但如果计算比较复杂的例子,得到的计算结果不完整。看上去像是有些计算循环没有完成。
请问这是do while引起的吗?还是可能其他的原因? 可是我并不知道循环次数,只能用do while。而且,我只是各用一thread完成一半的工作,至于每一半里面我不需要并行。

program test
use omp_lib
......

call omp_set_num_threads (2)
......

!$OMP PARALLEL
if (omp_get_thread_num()==0) then
do while(条件)
这里调用了一些subroutine.完成计算并储存结果到矩阵X1
end do
else
do while(条件)
调用同样的subroutine,但用了不同的变量。完成计算并储存结果到矩阵X2。
end do
end do
!$OMP BARRIER
!$OMP END PARALLEL
合并X1和X2,输出结果。

...全文
1213 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
intel_iclifort 2011-11-10
  • 打赏
  • 举报
回复
又一个很有意思的老帖,顶上来
risca 2009-07-21
  • 打赏
  • 举报
回复
学习了
janeyxm 2008-10-16
  • 打赏
  • 举报
回复
谢谢 intel_www,谢谢你推荐的工具!!终于找到问题了!
原来是我定义的矩阵C,在subroutine里面不只是读取而是赋值所以冲突了~~!太感谢了!!
intel_www 2008-10-16
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 janeyxm 的回复:]
谢谢 intel_www,谢谢你推荐的工具!!终于找到问题了!
原来是我定义的矩阵C,在subroutine里面不只是读取而是赋值所以冲突了~~!太感谢了!!
[/Quote]

呵呵,不用谢。对了,忘了这几个问题:“call omp_set_num_threads (2) ,然后code里面分配了thread 0做什么什么,thread 1做什么什么,那每个thread里面做的其实就是 按照serial program来做的对吧? 无所谓有几个cpu?”

"call omp_set_num_threads(2)"表示让OpenMP的runtime library创建两个工作线程来执行并行区域内的代码,在你的例子中就是!$OMP PARALLEL和 !$OMP End parallel 之间的代码段。也就是说两个工作线程执行的代码段是同一段代码。然而,你在这段代码中用了一个if语句来根据omp_get_thread_num()的返回值来做判断。这个调用返回的是当前工作线程在OpenMP所创建的线程组中的ID(注意:不要和操作系统的线程ID相混淆)。由于不同的工作线程有不同的ID,他们会转向不同的if-else分支,一个执行if,一个执行else。于是,这两个分支会被系统调用到不同的CPU Core上并行执行。
janeyxm 2008-10-13
  • 打赏
  • 举报
回复
上面贴的格式不对,不方便阅读。这个好一些。

!$OMP PARALLEL
if (omp_get_thread_num()==0) then

call eqsets(C,Y1,n,k,A,B,slctM1(1,:))

call AGGJE(C,k,Y1,L1,JS1)
m1=0
if(L1.EQ.1) then
Prod1=matmul(A,Y1)
p1=0
do j=1,n+k
if((Prod1(j).GE.B(j)).OR.((B(j)-Prod1(j)).LT.0.001)) then
p1=p1+1
endif
end do
if(p1.EQ.n+k) then
m1=m1+1
X1(:,m1)=Y1
endif
end if

s1=1
do i=0,k-3
s1=s1*slctM1(1,n+k-i)
end do

do while (s1==0)
call fslct(slctM1,n+k)
call eqsets(C,Y1,n,k,A,B,slctM1(2,:))
call AGGJE(C,k,Y1,L1,JS1)

if(L1.EQ.1) then
Prod1=matmul(A,Y1)
L1=0
call check(Prod1,B,n,k,m1,Y1,X1,L1)
if(L1==1) then
m1=m1+1
X1(:,m1)=Y1(:)
end if
end if
slctM1(1,:)=slctM1(2,:)

s1=1
do i=0,k-3
s1=s1*slctM1(1,n+k-i)
end do
end do

else
call eqsets(C,Y2,n,k,A,B,slctM2(1,:))

call AGGJE(C,k,Y2,L2,JS2)
m2=0

if(L2.EQ.1) then
Prod2=matmul(A,Y2)
p2=0
do j=1,n+k
if((Prod2(j).GE.B(j)).OR.((B(j)-Prod2(j)).LT.0.001)) then
p2=p2+1
endif
end do

if(p2.EQ.n+k) then
m2=m2+1
X2(:,m2)=Y2
endif
end if

s2=1
do i=0,k-2
s2=s2*slctM2(1,n+k-i)
end do

do while (s2==0)
call fslct(slctM2,n+k)
call eqsets(C,Y2,n,k,A,B,slctM2(2,:))

call AGGJE(C,k,Y2,L2,JS2)
if(L2.EQ.1) then
Prod2=matmul(A,Y2)
L2=0
call check(Prod2,B,n,k,m2,Y2,X2,L2)


if(L2==1) then
m2=m2+1
X2(:,m2)=Y2(:)
end if
end if

slctM2(1,:)=slctM2(2,:)

s2=1
do i=0,k-2
s2=s2*slctM2(1,n+k-i)
end do
end do
end if
!$OMP BARRIER
!$OMP End parallel
janeyxm 2008-10-13
  • 打赏
  • 举报
回复
谢谢楼上~~
你是说 可能我在两个部分都给相同的变量赋值,所以造成冲突吗? 可是我在每个部分都使用了不同的变量,如果用到相同的变量,也只是读取不赋值。
以下是部分代码。其中矩阵C,A,B和常数n,k只是读取不赋值。
另外,我想问,call omp_set_num_threads (2) ,然后code里面分配了thread 0做什么什么,thread 1做什么什么,那每个thread里面做的其实就是 按照serial program来做的对吧? 无所谓有几个cpu?

!$OMP PARALLEL
if (omp_get_thread_num()==0) then

call eqsets(C,Y1,n,k,A,B,slctM1(1,:))

call AGGJE(C,k,Y1,L1,JS1)
m1=0
if(L1.EQ.1) then
Prod1=matmul(A,Y1)
p1=0
do j=1,n+k
if((Prod1(j).GE.B(j)).OR.((B(j)-Prod1(j)).LT.0.001)) then
p1=p1+1
endif
end do
if(p1.EQ.n+k) then
m1=m1+1
X1(:,m1)=Y1
endif
end if

s1=1
do i=0,k-3
s1=s1*slctM1(1,n+k-i)
end do

do while (s1==0)
call fslct(slctM1,n+k)
call eqsets(C,Y1,n,k,A,B,slctM1(2,:))
call AGGJE(C,k,Y1,L1,JS1)

if(L1.EQ.1) then
Prod1=matmul(A,Y1)
L1=0
call check(Prod1,B,n,k,m1,Y1,X1,L1)
if(L1==1) then
m1=m1+1
X1(:,m1)=Y1(:)
end if
end if
slctM1(1,:)=slctM1(2,:)

s1=1
do i=0,k-3
s1=s1*slctM1(1,n+k-i)
end do
end do

else
call eqsets(C,Y2,n,k,A,B,slctM2(1,:))

call AGGJE(C,k,Y2,L2,JS2)
m2=0

if(L2.EQ.1) then
Prod2=matmul(A,Y2)
p2=0
do j=1,n+k
if((Prod2(j).GE.B(j)).OR.((B(j)-Prod2(j)).LT.0.001)) then
p2=p2+1
endif
end do

if(p2.EQ.n+k) then
m2=m2+1
X2(:,m2)=Y2
endif
end if

s2=1
do i=0,k-2
s2=s2*slctM2(1,n+k-i)
end do

do while (s2==0)
call fslct(slctM2,n+k)
call eqsets(C,Y2,n,k,A,B,slctM2(2,:))

call AGGJE(C,k,Y2,L2,JS2)
if(L2.EQ.1) then
Prod2=matmul(A,Y2)
L2=0
call check(Prod2,B,n,k,m2,Y2,X2,L2)


if(L2==1) then
m2=m2+1
X2(:,m2)=Y2(:)
end if
end if

slctM2(1,:)=slctM2(2,:)

s2=1
do i=0,k-2
s2=s2*slctM2(1,n+k-i)
end do
end do
end if
!$OMP BARRIER
!$OMP End parallel
intel_www 2008-10-13
  • 打赏
  • 举报
回复
建议你用Intel Thread Checker检查一下吧。像这种变量较多,数据共享情况不易看清楚地程序,Thread Checker可以有效的帮助检查出有没有冲突。至于怎样获取和使用Thread Checker可以参见顶置的Intel工具索引贴。
intel_www 2008-10-12
  • 打赏
  • 举报
回复
lz的例子是按功能划分的并行,不是按数据集划分的并行。这里建议使用OpenMP中的SECTIONS字句,最好不要轻易使用OpenMP runtime library中的函数,因为这样的函数调用容易引起可移植性和缩放性方面的问题。

这里结果不正确可能是由于两部分循环操作的数据集有冲突。对于存在数据竞争的地方应该加以保护。
janeyxm 2008-10-09
  • 打赏
  • 举报
回复
谢谢楼上~~!!

可好像是Fortran里面没有for循环。不过有forall。用法和for很像。forall(i<N,条件)。我的问题在于不知道循环次数的上限,而且很有可能我的循环次数N会远远超过integer的最大上限。所以我用了do while。
youxia000 2008-10-09
  • 打赏
  • 举报
回复
do while 不适合 用omp

能不能改成for的? 并行的要求就是 每次计算先后不相关
1. 设计目的、意义(功能描述) 蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是二十世纪四十年代中期由于科学技术的发展和电子计算机的发明,而被提出的一种以概率统计理论为指导的一类非常重要的数值计算方法。本次大作业主要是对蒙特·卡罗方法进行并行处理,通过OpenMP、MPI、.NET、Java、Win32API等一系列并行技术和并行机制对该算法进行并行处理,从而也进一步熟悉了蒙特·卡罗方法的串行算法和并行算法,实现了用蒙特·卡罗方法计算出半径为1单位的球体的体积,体会到了并行技术在实际生活中的应用。 2. 方案分析(解决方案) 蒙特·卡罗方法(Monte Carlo method)是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。球的体积可以估算为:位于点模型内随机点个数与全体随机点个数的比值乘以包围盒的体积算的。 3. 设计分析 3.1 串行算法设计 假定球体用B表示,半径r=1单位,B1是包含B的参考立方体(在本例中是边长为2的正方体),在B1中产生N个均匀分布的伪随机点。对每个随机点检测其是否在B内,假设位于B内的随机点个数为N(in)(<=N),应用蒙特卡洛算法,则B的体积为 V=V1(N(in)/N) 其中V1是B1的体积。如果产生足够多的随机点,理论上可以获得任意逼近精度。 算法描述如下: BEGIN N=_MAX; FOR I=0;I<_MAX;I++ X=RANDOM(); Y=RANDOM(); Z=RANDOM(); IF (X*X+Y*Y+Z*Z)<=1 COUNT++; END IF; END FOR; BULK=V1*(COUNT/_MAX); END; 本算法主要是在参考立方体的选取上和定义的_MAX的值对结果影响较大,所以应该选择合适的数。 3.2 并行算法设计 对FOR循环进行划分使用两个处理器完成计算。例如对一个长为n的序列,首先划分得到两个长为n/2的序列,将其交给两个处理器分别处理;而后进一步划分得到四个长为n/4的序列,再分别交给四个处理器处理;如此递归下去最终得到结果。当然这是理想的划分情况,如果划分步骤不能达到平均分配的目的,那么结果的效率会相对较差。 伪代码如下: BEGIN N=_MAX; FOR1 I=0;I<_MAX/2;I++ X1=RANDOM(); Y1=RANDOM(); Z1=RANDOM(); IF (X1*X1+Y1*Y1+Z1*Z1)<=1 COUNT1++; END IF; END FOR1; FOR2 I=_MAX/2+1;I<_MAX;I++ X2=RANDOM(); Y2=RANDOM(); Z2=RANDOM(); IF (X2*X2+Y2*Y2+Z2*Z2)<=1 COUNT2++; END IF; END FOR2; BULK=V1*((COUNT1+ COUNT2)/_MAX); END; 3.3 理论加速比分析 实验中大量数据所产生的加速比比小量数据所产生的加速比要体现得更明显,并且数据生成的并行加速比随着处理器核的增加而增加。设处理器个数为p,数据量为n,由于正常情况下该快速排序算法的复杂度为O(nlogn),并行处理的时间复杂度为O(klogk),其中k=n/p,所以并行算法的时间复杂度为O((n/p)log(n/p)),理论加速比为nlogn/((n/p)log(n/p))=p+logp. 4. 功能模块实现与最终结果分析 4.1 基于OpenMP的并行算法实现 4.1.1 主要功能模块与实现方法 利用了OpenMP里面的#omp parallel sections将对两个for循环用两个线程并行化执行,以多线程方式并行运行程序,并行的算法步骤如下: (1)初始化_max = 10000000; (2)创建两个线程; (3)由OpenMP编译指导语句控制产生并行执行代码区段; (4)将数据存放到tianqing_count; (5)各线程调用算法得出结果; 并行算法的部分代码如下: #pragma omp parallel for private(tianqing_x,tianqing_y,tianqing_z) reduction(+:tianqing_count2) for (tianqing_i = 0; tianqing_i work2.pSumto(c, 0, MAXN - 1)); Thread newthread2 = new Thread(thread2); stopwatch.Start(); 启动线程1和线程2; 等待进程结束; stopwatch.Stop(); 得到结果; 4.5.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.6~2.7左右。 4.6 并行计算技术在实际系统中的应用 4.6.1 主要功能模块与实现方法 该飞机订票系统主要实现了对机票的一些基本信息进行存储和管理的功能。在系统中实现了对机票信息的增删改查,考虑到查询的方便性,对机票按照航班号进行排序,而此排序方法用并行快速排序运用进来。利用OpenMP的并行技术,对机票信息按顺序排列好,并分析了实验过程中的加速比。 4.6.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:当数据量比较大时,加速比理论在1.9左右。数据量较大时体现出来的加速比更准确。由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.2~2.4左右。 5. 设计体会 虽然没有按时完成作业,但这份报告花了我好几天的时间,从开始的搭建并行计算平台到最后的程序运行成功可以说是对我的一个锻炼。每一次的遇到问题与每一次的解决问题都是一个成长。每一次遇到问题和解决问题都是一种锻炼,一种尝试,从我们上并行计算课我懂得了很多电脑硬件和软件的知识,这些可能对于我们这个专业以后都是没有机会接触的,所以我觉得选择了并行计算与多核多线程技术这门课是非常正确的。对OpenMP、MPI、WIN32API、Java、.NET的并行技术有了一定的了解。在搭建MPI并行程序这块,学习的知识尤为增加,这些都是在不断的摸索、学习中学会的。 这次的大作业虽然是对以前实验的整合,但它加深了我对并行计算的印象,也使我对并行计算知识的理解更加深刻,也使我认识到了自己很多不足之处。学习并行计算的历程不会因为完成本次大作业而停止,我们是为了用知识武装大脑而学习,通过学习充实自己的生活,要努力学习,争取以后能够完成规模更大的程序。
1. 设计目的、意义(功能描述) 蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是二十世纪四十年代中期由于科学技术的发展和电子计算机的发明,而被提出的一种以概率统计理论为指导的一类非常重要的数值计算方法。本次大作业主要是对蒙特·卡罗方法进行并行处理,通过OpenMP、MPI、.NET、Java、Win32API等一系列并行技术和并行机制对该算法进行并行处理,从而也进一步熟悉了蒙特·卡罗方法的串行算法和并行算法,实现了用蒙特·卡罗方法计算出半径为1单位的球体的体积,体会到了并行技术在实际生活中的应用。 2. 方案分析(解决方案) 蒙特·卡罗方法(Monte Carlo method)是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。球的体积可以估算为:位于点模型内随机点个数与全体随机点个数的比值乘以包围盒的体积算的。 3. 设计分析 3.1 串行算法设计 假定球体用B表示,半径r=1单位,B1是包含B的参考立方体(在本例中是边长为2的正方体),在B1中产生N个均匀分布的伪随机点。对每个随机点检测其是否在B内,假设位于B内的随机点个数为N(in)(<=N),应用蒙特卡洛算法,则B的体积为 V=V1(N(in)/N) 其中V1是B1的体积。如果产生足够多的随机点,理论上可以获得任意逼近精度。 算法描述如下: BEGIN N=_MAX; FOR I=0;I<_MAX;I++ X=RANDOM(); Y=RANDOM(); Z=RANDOM(); IF (X*X+Y*Y+Z*Z)<=1 COUNT++; END IF; END FOR; BULK=V1*(COUNT/_MAX); END; 本算法主要是在参考立方体的选取上和定义的_MAX的值对结果影响较大,所以应该选择合适的数。 3.2 并行算法设计 对FOR循环进行划分使用两个处理器完成计算。例如对一个长为n的序列,首先划分得到两个长为n/2的序列,将其交给两个处理器分别处理;而后进一步划分得到四个长为n/4的序列,再分别交给四个处理器处理;如此递归下去最终得到结果。当然这是理想的划分情况,如果划分步骤不能达到平均分配的目的,那么结果的效率会相对较差。 伪代码如下: BEGIN N=_MAX; FOR1 I=0;I<_MAX/2;I++ X1=RANDOM(); Y1=RANDOM(); Z1=RANDOM(); IF (X1*X1+Y1*Y1+Z1*Z1)<=1 COUNT1++; END IF; END FOR1; FOR2 I=_MAX/2+1;I<_MAX;I++ X2=RANDOM(); Y2=RANDOM(); Z2=RANDOM(); IF (X2*X2+Y2*Y2+Z2*Z2)<=1 COUNT2++; END IF; END FOR2; BULK=V1*((COUNT1+ COUNT2)/_MAX); END; 3.3 理论加速比分析 实验中大量数据所产生的加速比比小量数据所产生的加速比要体现得更明显,并且数据生成的并行加速比随着处理器核的增加而增加。设处理器个数为p,数据量为n,由于正常情况下该快速排序算法的复杂度为O(nlogn),并行处理的时间复杂度为O(klogk),其中k=n/p,所以并行算法的时间复杂度为O((n/p)log(n/p)),理论加速比为nlogn/((n/p)log(n/p))=p+logp. 4. 功能模块实现与最终结果分析 4.1 基于OpenMP的并行算法实现 4.1.1 主要功能模块与实现方法 利用了OpenMP里面的#omp parallel sections将对两个for循环用两个线程并行化执行,以多线程方式并行运行程序,并行的算法步骤如下: (1)初始化_max = 10000000; (2)创建两个线程; (3)由OpenMP编译指导语句控制产生并行执行代码区段; (4)将数据存放到tianqing_count; (5)各线程调用算法得出结果; 并行算法的部分代码如下: #pragma omp parallel for private(tianqing_x,tianqing_y,tianqing_z) reduction(+:tianqing_count2) for (tianqing_i = 0; tianqing_i work2.pSumto(c, 0, MAXN - 1)); Thread newthread2 = new Thread(thread2); stopwatch.Start(); 启动线程1和线程2; 等待进程结束; stopwatch.Stop(); 得到结果; 4.5.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.6~2.7左右。 4.6 并行计算技术在实际系统中的应用 4.6.1 主要功能模块与实现方法 该飞机订票系统主要实现了对机票的一些基本信息进行存储和管理的功能。在系统中实现了对机票信息的增删改查,考虑到查询的方便性,对机票按照航班号进行排序,而此排序方法用并行快速排序运用进来。利用OpenMP的并行技术,对机票信息按顺序排列好,并分析了实验过程中的加速比。 4.6.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:当数据量比较大时,加速比理论在1.9左右。数据量较大时体现出来的加速比更准确。由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.2~2.4左右。 5. 设计体会 虽然没有按时完成作业,但这份报告花了我好几天的时间,从开始的搭建并行计算平台到最后的程序运行成功可以说是对我的一个锻炼。每一次的遇到问题与每一次的解决问题都是一个成长。每一次遇到问题和解决问题都是一种锻炼,一种尝试,从我们上并行计算课我懂得了很多电脑硬件和软件的知识,这些可能对于我们这个专业以后都是没有机会接触的,所以我觉得选择了并行计算与多核多线程技术这门课是非常正确的。对OpenMP、MPI、WIN32API、Java、.NET的并行技术有了一定的了解。在搭建MPI并行程序这块,学习的知识尤为增加,这些都是在不断的摸索、学习中学会的。 这次的大作业虽然是对以前实验的整合,但它加深了我对并行计算的印象,也使我对并行计算知识的理解更加深刻,也使我认识到了自己很多不足之处。学习并行计算的历程不会因为完成本次大作业而停止,我们是为了用知识武装大脑而学习,通过学习充实自己的生活,要努力学习,争取以后能够完成规模更大的程序。

566

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧