Fortran 并行运算
虽然前面也有几个博客整理了python以及Julia的并行计算,但是Fortran的并行计算自己也一直在摸索中,因为这里会涉及到进程之间通讯的问题,正好最近得到了别人写的一段并行代码,通过研究还是很快的搞清楚了如何利用Fortran来进行并行运算,这里就把代码和自己的一些笔记整理出来.
并行思想
先来认真的描述一下我在整理代码过程中的,怎么把一个程序分拆成并行.
这里要对多重循环的结构进行并行,是因为fortran的串行执行的时候,只会调用单个进程来计算,速度上会非常慢,如果可以将计算机上可用进程全部调动起来,就会大大提高执行效率.
源代码
1 | program main |
代码解释
test这个子过程是拿来做测试说明的,可以看到它是一个多重循环结构,最终计算的结果会存储在re中,作为计算返回的结果.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 subroutine test(delta,firstRx,npc,re)
implicit none
integer npc,nthe,i1,i2,i3,i4
real*8 firstRx,re(npc),dthe,delta,R
real*8 re1
parameter(nthe=100)
dthe = 3.1415926d0/nthe
R = firstRx + delta*npc
re1 = 0
! write(*,111)firstRx,1.0*npc,R
do i1 = 1,npc
do i2 = 1,npc
do i3 = 1,npc
do i4 = 1,npc
re1 = re1 + cos(sin(1.0*i1) + cos(2.0*i2) + sin(1.0*i3) + cos(1.0*i4))
end do
end do
end do
re(i1) = cos(firstRx)*sin(1.0*i1) + re1
end do
111 format(3f16.2)
return
end subroutine test
在主程序中,对不同的进程都会得到不同的my_rank这个值,根据不同的my_rank可以得到不同的firstRx,这个变量最后会作为参数输入到test这个自过程中,也正是通过my_rank,firstRx这两个变量的结合,来实现前面提到的,将整个计算区间分成一系列离散的区间,而且离散区间的数目会和开启的进程数目相同,从而实现在每个进程上分别计算不同离散区间的结果.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15call MPI_INIT(ierr) ! 初始化进程
call MPI_COMM_RANK(MPI_COMM_WORLD, my_rank, ierr) ! 得到本进程在通信空间中的rank值,即在组中的逻辑编号(该 rank值为0到p-1间的整数,相当于进程的ID。)
call MPI_COMM_SIZE(MPI_COMM_WORLD, p, ierr) !获得进程个数 size, 这里用变量p保存
call MPI_Barrier(MPI_COMM_WORLD,ierr)
!------------------------
! write(*,*)"mu_rank = ",my_rank
! write(*,*)"Number of process = ",p
npc = anint(1.0*ntotal/p) ! 四舍五入取整
delta = 0.50d0
! 这里通过这个设置,使得不同进程执行不同区间的计算,最后通过MPI_GATHER来将所有的结果收集到一起,得到最终的计算结果
! 不同的进程对应的my_rank这个值不同,从而反应在firstRx这个参数上,
! firstRx = my_rank*npc*delta + 15.0d0
firstRx = my_rank*npc*delta
call test(delta,firstRx,npc,re)
最后,将所有进程计算得到的结果re收集到一起,得到最终的计算结果re1
2! 将所有进程结果re(第一个参数)都收集到re(第四个参数)中,此时不同进程中数据长度应该相同
call MPI_GATHER(re,npc,MPI_real8,re,npc,MPI_real8,0,MPI_COMM_WORLD,ierr)
并将得到的结果进行数据保存1
2
3
4
5
6
7if (my_rank .EQ. 0) then
open(1,file='result.dat')
do i = 1,npc*p
write(1,*),re(i)
end do
endif
close(1)
这里要注意,既然是要并行,那么你需要并行的那段程序,一定是串行执行的时候需要耗费一定时间的,否则你就没必要并行.
{:.warning}
比如你有一个简单的循环1
2
3do i4 = 1,npc
re1 = sin(1.0*i4)
end do
这种就完全不必要并行了,就算是并行了也会报错,因为执行时间太短了,进程间的通讯时间可能都会比执行时间要长.
编译执行
我是利用mpif90进行编译的1
mpif90 filename.f90 -o f1.out
并行执行1
mpirun -np 10 f1.out &
此时会开启10个进程来执行这个程序,一般在并行执行程序的时候,最好知道电脑上可用的进程数目是多少,这样可以将所有的进程都调用起来进行计算.
鉴于该网站分享的大都是学习笔记,作者水平有限,若发现有问题可以发邮件给我
- yxliphy@gmail.com
也非常欢迎喜欢分享的小伙伴投稿