fortran并行入门(mpi)(一)

文章目录

    • 安装oneAPI
    • 简单的并行
    • 通过线程之间的通信使程序按顺序输出

暂且开个坑,边用边学,实用至上。

安装oneAPI

Intel oneAPI Base Toolkit
Intel oneAPI HPC Toolkit

简单的并行

program main
    use mpi
    implicit none
    integer*4::ierr,my_id,num_procs
    call MPI_INIT ( ierr )
  ! find out my process ID, and how many processes were started.
    call MPI_COMM_RANK (MPI_COMM_WORLD, my_id, ierr)
    call MPI_COMM_SIZE (MPI_COMM_WORLD, num_procs, ierr) !num_procs--number of process
    write(*,'(1x,i2,a,i2)')my_id,'/',num_procs

    call MPI_FINALIZE ( ierr )
end program

注意编译要用mpiifort:

mpiifort test.f90 -o test

运行要用mpirun

mpirun -np 8 ./test

运行结果为

  1/ 8
  3/ 8
  4/ 8
  5/ 8
  6/ 8
  7/ 8
  0/ 8
  2/ 8

从上面简单的实例可以看出,子程序MPI_COMM_RANK的第二个参量my_id输出线程序号,是从0计数的,而子程序MPI_COMM_SIZE的第二个参量num_procs输出总的线程数。从打印结果可以看出,各个线程运行是是互不干扰的并行运行的,所以我们可以将my_id作为标识符,在处理一些互补干扰的事件时可以很容易地采用并行mpi库来让它并行执行。它的运行效率总是要远高于单线程的。
比如下面是我实际计算时的一个代码片段

indcal=(/1,2,3,4,6,19,17/)
   do i=0,int(7/num_procs)
     k=i*num_procs+my_id+1
     if(k<8)then
     temp1=p1%rel_E_f(indcal(k),n,bigl)
     do j=1,5
       temp2=p1%gfactor(j)
       write(*,'(1x,i2,2x,a,3i3,4e30.20)')k,trim(vname(indcal(k))),nint(Z),nint(A),j,energy(n-1+j),energy(n-1+j)-enk(j+l,kk),temp2,temp2-gnk(j+l,kk)
     enddo
     endif
   enddo

这样的处理,不管是4线程还是8线程还是单线程都可以正常运行并输出需要的结果。但由于各线程间是没有通信的,所以输出结果的顺序是乱的。

通过线程之间的通信使程序按顺序输出

这里用到两个子程序,发送:mpi_send,接收mpi_recv,它们的第四个参数都是线程序号,分别代表发送目标和接收目标。
如下

program main
    use mpi
    implicit none
    integer*4::ierr,my_id,num_procs,i,tempa,status(mpi_status_size),tt,j
    call MPI_INIT ( ierr )
  ! find out my process ID, and how many processes were started.
    call MPI_COMM_RANK (MPI_COMM_WORLD, my_id, ierr)
    call MPI_COMM_SIZE (MPI_COMM_WORLD, num_procs, ierr) !num_procs--number of process
    
    tempa=my_id
    if(my_id==0)then
        write(*,'(1x,i2,a,3i2)')my_id,'/',num_procs,mod(my_id+1,num_procs),mod(my_id-1+num_procs,num_procs)
        call mpi_send(tempa,1,mpi_integer,mod(my_id+1,num_procs),99,mpi_comm_world,ierr)
    else
        call mpi_recv(tempa,1,mpi_integer,mod(my_id-1+num_procs,num_procs),99,mpi_comm_world,status,ierr)
        write(*,'(1x,i2,a,3i2)')my_id,'/',num_procs,mod(my_id+1,num_procs),mod(my_id-1+num_procs,num_procs)
    endif
    if(my_id

输出结果

  0/ 8 1 7
  1/ 8 2 0
  2/ 8 3 1
  3/ 8 4 2
  4/ 8 5 3
  5/ 8 6 4
  6/ 8 7 5
  7/ 8 0 6

利用这两个子程序可以实现线程之间的通信,这样我们就可以将一些更复杂的程序改成并行的形式运行了。
另外,C/C++版本的mpi库函数也是类似的用法。

你可能感兴趣的:(Fortran,探索,笔记,多线程,算法)