回 帖 发 新 帖 刷新版面

主题:Fortran+OpenMP并行后,结果不一样了

最近老师要求我给一个Fortran代码做OpenMP并行,我给以下这段代码添加OpenMP并行后,结果和串行的结果就不一样了,不知道数据冲突在哪?
    eoshift这个函数我测试了,是不影响TMIX数组的,唯一可能冲突就是TX的写入,但写入也是写入数组的不同部分,应该不会产生冲突。很奇怪,希望大家指教一下。

!$OMP PARALLEL SHARED(TX,TY,KMASKE,KMASKN,TMIX,bid,kn),PRIVATE(n)
!$OMP DO
      do n=1,nt

         TX(:,:,kn,n,bid) = KMASKE* &
                (eoshift(TMIX(:,:,k,n),dim=1,shift=1) - TMIX(:,:,k,n))
         TY(:,:,kn,n,bid) = KMASKN* &
                (eoshift(TMIX(:,:,k,n),dim=2,shift=1) - TMIX(:,:,k,n))

       end do
!$OMP END DO
!$OMP END PARALLEL

回复列表 (共6个回复)

沙发

从这点程序及楼主的描述来看,没发现问题,不知是否给出楼主的测试结果

板凳

数组比较大,而且在整个运算过程中调用了50次,我只选其中有数据而且不为0几行表示。(一共50次调用,前几次的结果,串行和OpenMP并行是一样的,但后面就开始不一样了,这也是很令我困惑的地方)
 这是串行后,不为0的几行结果
  2.828574513173976E-004  2.595476796898311E-004  3.045061688453643E-004
  2.650917005624365E-004  2.883143028000745E-004  2.592413037412200E-004
  2.770419240185618E-004  2.653249571658023E-004  2.680191959747447E-004
  2.757387953522539E-004  2.700915246656166E-004  2.915743717686325E-004
  2.653667462233500E-004  2.965858016601430E-004  2.602235178414958E-004
  2.976231813001107E-004  2.140697455246254E-004  3.691044675377952E-004
  1.983555071731757E-004  3.156382549747150E-004  7.495622355335740E-005
 -3.124432473914140E-003 -7.399056181835562E-003 -1.059552911424788E-002
 这是OpenMP并行后,相同部分的结果
  2.829394003214247E-004  2.593990233954457E-004  3.043918736160833E-004
  2.634389900393330E-004  2.896412801725035E-004  2.565555544791209E-004
  2.735754110432254E-004  2.556739792574092E-004  2.712598935410426E-004
  2.742506031729874E-004  2.781287174364877E-004  2.918353086478476E-004
  2.649669166210344E-004  2.968000808358795E-004  2.599204513025200E-004
  2.977982511893629E-004  2.137980499199443E-004  3.690522064054846E-004
  1.996156382126912E-004  3.247705287350300E-004  1.093902048943107E-004
 -3.098580334334855E-003 -7.441593649467393E-003 -1.069361981823747E-002

3 楼

1. 如果不是很麻烦的话最好声明default(none), 你的k没有定义是私有还是共有. 不过默认一般是共有.
2. omp并行回大乱循环的数序, 所以截断误差会导致最后几位不同(如前面几个数据).
3. 这是我所怀疑的, 函数eoshift是否对误差很敏感, 会否在50次循环之后高速放大了误差?
4. 函数eoshift是否是线程安全的.

4 楼

   单单是循环的话,nt循环的次数并不高,nt的值大概在2到10左右吧。50次是调用这个循环的次数。每次输入的值都不一样,应该不会放大误差(估计)。
   eoshift函数是F90自带的函数,具体的含义是:
   EOSHIFT(array,shift[,boundary][,dim]) 在指定维上替换掉数组末端,复制边界值到数组末尾。
   Fortran自带的函数感觉应该没有问题。
   所以,截断误差这个我之前还真没想过,这是OpenMP并行一定会产生的么?那对于高精度的运算来说,使用OpenMP不是特别不安全么?
   

5 楼

截断误差是所有浮点数运算都会有的. 只是omp会改变计算的顺序而导致跟串行算出来的截断误差不同. 当然例如有大数吃小数这些运算,为了避免这种情况,是需要在计算上有一个固定顺序的, 既然固定了顺序就不能用omp. 但总的来讲这不是omp的问题. 故精度要求与是否使用omp无关.

EOSHIFT这个函数我没用使用过, 内部函数的话应该是线程安全的, 但我也不确信这点, 各家恐怕有不同的实现方法.

你的意思是调用这个并行区的次数是50次吧? 那恐怕还要看看循环外的运算是否对初值敏感. 已经影响到有效数字第3甚至第2未是比较严重了.

6 楼

误差范围内的结果不同是正常的,因为这是并行计算。

数值计算并不满足结合律,a+(b+c) 与 (a+b)+c,结果可能不一样,原因就是上面说的有截断误差。从1加到100,串行就是从1到100挨个加起来,并行是这100个数以随机的顺序地加起来。

并行计算也是对算法稳定性的一种校验,如果并行计算的结果每次都相差较大,那么你的串行的结果其实也是错的 。

我来回复

您尚未登录,请登录后再回复。点此登录或注册