计算化学公社

 找回密码 Forget password
 注册 Register
楼主 Author: wxhwbh
打印 Print 上一主题 Last thread 下一主题 Next thread

[Fortran] Fortran OpenMP求助 第二弹

[复制链接 Copy URL]

831

帖子

1

威望

7183

eV
积分
8034

Level 6 (一方通行)

16#
发表于 Post on 2020-6-12 22:08:47 | 只看该作者 Only view this author
wxhwbh 发表于 2020-6-12 22:07
不行,不用ORDERED的结果不对,上面那个输出是带ORDERED的。不带的是这样

这样看好像又在一个线程内, ...

是啊,就是在一个线程内。结果不对一定是你别的地方有问题。

用了ordered,等同于串行,结果当然对了。

403

帖子

4

威望

2874

eV
积分
3357

Level 5 (御坂)

17#
发表于 Post on 2020-6-13 11:05:21 | 只看该作者 Only view this author
同建议用MPI。

MPI默认变量全部为private,并且会严格按照用户指定的方式计算。

评分 Rate

参与人数
Participants 1
eV +2 收起 理由
Reason
thanhtam + 2 我很赞同

查看全部评分 View all ratings

257

帖子

4

威望

4967

eV
积分
5304

Level 6 (一方通行)

18#
 楼主 Author| 发表于 Post on 2020-6-13 16:12:41 | 只看该作者 Only view this author
hebrewsnabla 发表于 2020-6-12 22:08
是啊,就是在一个线程内。结果不对一定是你别的地方有问题。

用了ordered,等同于串行,结果当然对了 ...

我再检查了一下发现,可能是采样的问题。我在sub1内部的最后让他输出采样结果,再在sub2内部的开头让它输出读到的采样结果,结果发现它们不一样:
  1. ...
  2. test1  -2.10577516073414        35.3110685664510                1
  3. test2  -2.10584454662873        35.2900101209847                1
  4. test1 -5.935277974994733E-002   129.545758530043                0
  5. test2 -5.954648581507676E-002   129.544568183094                0
  6. test1 -0.104941126661693       -25.3967090962898                2
  7. test2 -0.104820942496785       -25.3998545087038                2
  8. test1  -3.55467247470428       -129.492075198021                1
  9. test2  -3.55433312249038       -129.563165448924                1
  10. test1   1.90850527754983        354.316392485028                0
  11. test2   1.90750004729617        354.373622420096                0
  12. test1 -0.761451748837811        195.512064015400                3
  13. test2 -0.761838386826844        195.489210799541                3
  14. ...
复制代码

这里test1和test2分别为sub1和sub2的输出,后两个数是采样结果,最后一个integer是线程号。可以看出它们的差距比较大。如果是DO ORDERED则两者完全一致。但我不明白为什么它们会不一样,而且因为采样的数据是需要演化的,又不能设为SHARED,这种情况应该怎么解决呢?
贫困U 退学与疯子工程学院

831

帖子

1

威望

7183

eV
积分
8034

Level 6 (一方通行)

19#
发表于 Post on 2020-6-13 16:48:27 | 只看该作者 Only view this author
wxhwbh 发表于 2020-6-13 16:12
我再检查了一下发现,可能是采样的问题。我在sub1内部的最后让他输出采样结果,再在sub2内部的开头让它输 ...

没有细节没法说。

403

帖子

4

威望

2874

eV
积分
3357

Level 5 (御坂)

20#
发表于 Post on 2020-6-14 11:03:54 | 只看该作者 Only view this author
本帖最后由 万里云 于 2020-6-14 17:35 编辑

帮楼主用MPI改写了一下:
  1. use mpi ! 声明使用mpi模块

  2. integer :: world_size, world_rank, mpi_ierr ! 总进程数、当前进程ID、子程序返回状态


  3. ! 初始化
  4. call mpi_ini(mpi_ierr)

  5. ! 获取总进程数和当前进程ID
  6. call mpi_comm_size(mpi_comm_world, world_size, mpi_ierr)
  7. call mpi_comm_rank(mpi_comm_world, world_rank, mpi_ierr)

  8. do itraj=1, Ntraj
  9.     if (mod(itraj, world_size) == world_rank) then ! 根据itraj和总进程数的余数判断当前itraj由哪个进程处理
  10.         call sub1 !抽样
  11.         call sub2(itraj) !演化
  12.     end if
  13. end do

  14. ! 结束
  15. call mpi_finalize(mpi_ierr)
复制代码



评分 Rate

参与人数
Participants 2
eV +10 收起 理由
Reason
wxhwbh + 5 谢谢
hebrewsnabla + 5 哈哈哈,喂到嘴边了

查看全部评分 View all ratings

257

帖子

4

威望

4967

eV
积分
5304

Level 6 (一方通行)

21#
 楼主 Author| 发表于 Post on 2020-6-14 13:41:25 | 只看该作者 Only view this author
万里云 发表于 2020-6-14 11:03
帮楼主用MPI改写了一下:

谢谢,我也在试图学习MPI,看看能不能改成MPI并行。
好像对于动力学程序这种强调顺序的,OpenMP确实不太方便,以后还是量化程序用OpenMP,动力学程序用MPI吧......
贫困U 退学与疯子工程学院

257

帖子

4

威望

4967

eV
积分
5304

Level 6 (一方通行)

22#
 楼主 Author| 发表于 Post on 2020-6-14 15:41:32 | 只看该作者 Only view this author
万里云 发表于 2020-6-14 11:03
帮楼主用MPI改写了一下:

我试着按这个方法改写了程序,发现可以起到并行的作用,但最后输出的结果是正确结果的1/np倍(np是并行核数)。我的程序在演化这个部分是把最后的数据存储到一个数组P(i, j, itraj)里面,所有轨迹演化完了后对这个数组取一个轨迹系综平均:

  1. ... (前面是抽样演化部分)
  2. do i=1,M
  3.     do j=1, N
  4.         result(i,j)=sum(P(i,j,:))/Ntraj
  5.     end do
  6. end do
复制代码


我猜测是这一步出了问题。但我有一点不明白:如果在此之前已经用了mpi_finalize退出MPI环境,那么这一部分不应该是串行的吗?还会受到MPI的影响吗?另外我看有些MPI程序好像是用归约(REDUCE)的方法来求和,请问这种情况是否一定要用MPI的归约?

还有一个问题,我看到大部分的MPI教程都是说程序的开头必须用MPI_INIT,最后结束部分用MPI_FINALIZE。但我这个程序动力学只是一个subroutine,只在这个subroutine里使用MPI环境可以吗?或者说一个程序只把并行部分用MPI_INIT和MPI_FINALIZE框起来,那么可以保证只有这个部分是并行的,其他部分是串行的吗?非常感谢!
贫困U 退学与疯子工程学院

403

帖子

4

威望

2874

eV
积分
3357

Level 5 (御坂)

23#
发表于 Post on 2020-6-14 16:47:26 | 只看该作者 Only view this author
本帖最后由 万里云 于 2020-6-14 17:14 编辑
wxhwbh 发表于 2020-6-14 15:41
我试着按这个方法改写了程序,发现可以起到并行的作用,但最后输出的结果是正确结果的1/np倍(np是并行核 ...
openmp是“多线程”并行,进程还是只有一个,数据在线程间共享。而MPI是“多进程”并行,每个进程都是一个独立的程序,不共享数据。如果用top命令查看CPU占用,openmp是一个程序占用100%*N,而MPI是N个占用100%的程序。

如果把计算任务比作运货,CPU比做司机:openmp就是只有一辆卡车,干活时一拥而上;而MPI则是人手一辆卡车,每个人按工号分配任务,只在必要的时候交流信息。一拥而上省了买车的钱(内存),而且也不需要明确地分配任务(程序简单),适合短小的任务。但任务量一大,这种乱糟糟的管理方式就捉急了。人手一辆卡车既费钱,又需要花时间分配任务,但运作起来有条不紊,出了事容易追责,适合较大的任务。

如果需要汇总来自不同进程的数据,需要开辟一个working array并设为零,并行完成后再调用mpi_reduce或者mpi_all_reduce汇总到final array。

mpi_init必须在总程序一开始调用,同理mpi_finalize必须在总程序最后调用。一旦调用了mpi_finalize程序就退出了。

如果只在一个子程序内并行,可以用MPI_Comm_spawn动态创建进程,但估计挺复杂的。最好的办法是把主程序其它部分并行,串行部分只让主进程(world_rank==0)来干。

评分 Rate

参与人数
Participants 1
eV +5 收起 理由
Reason
wxhwbh + 5 谢谢

查看全部评分 View all ratings

257

帖子

4

威望

4967

eV
积分
5304

Level 6 (一方通行)

24#
 楼主 Author| 发表于 Post on 2020-6-15 10:57:19 | 只看该作者 Only view this author
万里云 发表于 2020-6-14 16:47
openmp是“多线程”并行,进程还是只有一个,数据在线程间共享。而MPI是“多进程”并行,每个进程都是一个 ...

谢谢您。程序大部分都没有问题了,但还有一个小问题:演化的第一步会生成一个随机数,但我检查发现MPI并行后并行的进程生成的随机数是一模一样的,也就是同时在跑的4个进程都生成了一样的随机数。我不是很理解,因为理论上这些变量不应该是private吗?这种情况要怎么处理呢?
贫困U 退学与疯子工程学院

831

帖子

1

威望

7183

eV
积分
8034

Level 6 (一方通行)

25#
发表于 Post on 2020-6-15 11:06:08 | 只看该作者 Only view this author
wxhwbh 发表于 2020-6-15 10:57
谢谢您。程序大部分都没有问题了,但还有一个小问题:演化的第一步会生成一个随机数,但我检查发现MPI并 ...

因为随机数种子是一样的。办法有很多,例如在主进程一次生成多个随机数,再scatter到每个进程;或者想办法使用不同的种子(这个不太容易)。

评分 Rate

参与人数
Participants 1
eV +2 收起 理由
Reason
wxhwbh + 2 谢谢

查看全部评分 View all ratings

403

帖子

4

威望

2874

eV
积分
3357

Level 5 (御坂)

26#
发表于 Post on 2020-6-15 11:20:57 | 只看该作者 Only view this author
wxhwbh 发表于 2020-6-15 10:57
谢谢您。程序大部分都没有问题了,但还有一个小问题:演化的第一步会生成一个随机数,但我检查发现MPI并 ...

MPI每个进程是同时启动的,随机函数生成器读取系统时间做种子值,种子值也是一样的。

试试用这个子程序初始化种子值:
  1.   subroutine init_random_seed()
  2.     implicit none
  3.     integer :: i, n, clock
  4.     integer, dimension(:), allocatable :: seed

  5.     call random_seed(size = n)
  6.     allocate(seed(n))

  7.     call system_clock(count=clock)

  8.     seed = clock / world_size * (world_rank + 1) &
  9.          + 37 * (/ (i - 1, i = 1, n) /)
  10.     call random_seed(put = seed)

  11.     deallocate(seed)
  12.   end subroutine
复制代码

评分 Rate

参与人数
Participants 1
eV +5 收起 理由
Reason
wxhwbh + 5 谢谢

查看全部评分 View all ratings

257

帖子

4

威望

4967

eV
积分
5304

Level 6 (一方通行)

27#
 楼主 Author| 发表于 Post on 2020-6-15 13:44:16 | 只看该作者 Only view this author
本帖最后由 wxhwbh 于 2020-6-15 13:53 编辑
万里云 发表于 2020-6-15 11:20
MPI每个进程是同时启动的,随机函数生成器读取系统时间做种子值,种子值也是一样的。

试试用这个子程 ...

谢谢,用了这个后确实能生成不同的随机数。
这个程序是什么原理呢?我好像在别的程序也见过类似的代码。另外这里的n是指进程数吗?
贫困U 退学与疯子工程学院

403

帖子

4

威望

2874

eV
积分
3357

Level 5 (御坂)

28#
发表于 Post on 2020-6-15 16:08:38 | 只看该作者 Only view this author
wxhwbh 发表于 2020-6-15 13:44
谢谢,用了这个后确实能生成不同的随机数。
这个程序是什么原理呢?我好像在别的程序也见过类似的代码。 ...

原理是把种子值根据进程ID做了运算,让不同进程的种子差别尽可能大。

这段程序的主体也是我抄来的,n是啥我也不清楚,那个莫名其妙的37是什么意思也不清楚。

本版积分规则 Credits rule

手机版 Mobile version|北京科音自然科学研究中心 Beijing Kein Research Center for Natural Sciences|京公网安备 11010502035419号|计算化学公社 — 北京科音旗下高水平计算化学交流论坛 ( 京ICP备14038949号-1 )|网站地图

GMT+8, 2024-11-23 19:02 , Processed in 0.203299 second(s), 21 queries , Gzip On.

快速回复 返回顶部 返回列表 Return to list