Fortran Coder

标题: 刚接触fortran和mpi,求助mpi_sendrecv的问题 [打印本页]

作者: bread31    时间: 2015-11-20 10:28
标题: 刚接触fortran和mpi,求助mpi_sendrecv的问题
一、在不使用if语句的时候,结果只有rank=0的输出,而rank=1堵死了
[Fortran] 纯文本查看 复制代码

    program main   
    implicit none
    include 'mpif.h'
    integer rank,ierr,status(mpi_status_size)
    integer i,j
    i=3
    j=5
    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world,rank,ierr)
    call mpi_send(i,1,mpi_integer,1,99,mpi_comm_world,ierr)
    write(*,1) rank,i,j
    call mpi_recv(j,1,mpi_integer,0,99,mpi_comm_world,status,ierr)
    write(*,1) rank,i,j
1  format(1x,'rank=',i3,5x,'i=',i3,5x,'j=',i3)
    call mpi_finalize(ierr)
    end

二、使用mpi_sendrecv时无论时卡住,无输出;不过如果将发送地址和接收地址都设置成0,倒是可以实现赋值功能(╯‵□′)╯
[Fortran] 纯文本查看 复制代码

    program main
    include 'mpif.h'
    integer rank,ierr,status(mpi_status_size)
    integer i,j
    i=3
    j=5
    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world,rank,ierr)
    call mpi_sendrecv(i,1,mpi_integer,1,99,j,1,mpi_integer,0,99,mpi_comm_world,status,ierr)
    write(*,1) rank,i,j
1  format(1x,'rank=',i3,'i=',i3,'j=',i3)
    call mpi_finalize(ierr)
    end
另外求大师推荐几本合适的书,方便初学者自学。谢谢大家!


作者: 珊瑚虫    时间: 2015-11-20 10:51
(1) 新手推荐都志辉的书《高性能计算之并行编程技术-MPI并行程序设计》 百度很容易下到
(2) 第一个程序的问题,首先要理解并发的概念,
如果没有if 假设你有两个进程,
第一个send语句,两个进程都要并发执行,要实现
a:0向1发送数据
b: 1向1发送数据
第二个两个进程都要并发执行,要实现
c: 0从0接收数据,
d:1从0接收数据;
看看这a,b,c,d 四个工作,你会发现,a对应d ,而b 没人对应 一直卡着,c 没人对应一直卡着。所以你得程序走不下去
(3)第二个程序是同样的问题,你虽然用的是sendrecv 但是每个进程执行的发送目标和接收目标都是相同的,本身接收和发送的就和上面一样不匹配,所以程序一直卡着不往下走。
作者: bread31    时间: 2015-11-20 10:57
珊瑚虫 发表于 2015-11-20 10:51
(1) 新手推荐都志辉的书《高性能计算之并行编程技术-MPI并行程序设计》 百度很容易下到
(2) 第一个程序 ...

非常感谢!第一个程序我理解问题所在了,但是第二个的问题通常都是怎么解决的啊,send和recv在同一个指令里,也没法用if呀……
作者: 珊瑚虫    时间: 2015-11-20 10:59
bread31 发表于 2015-11-20 10:57
非常感谢!第一个程序我理解问题所在了,但是第二个的问题通常都是怎么解决的啊,send和recv在同一个指令 ...

要看你实现什么样的功能,请先说清楚你要实现的功能。
作者: bread31    时间: 2015-11-20 11:04
珊瑚虫 发表于 2015-11-20 10:59
要看你实现什么样的功能,请先说清楚你要实现的功能。

初学者试指令,只是想实现把0的i发送给1的j……
作者: 珊瑚虫    时间: 2015-11-20 11:14
本帖最后由 珊瑚虫 于 2015-11-20 11:19 编辑

不喜欢用if那就用select case 吧,下面的程序完成的工作是:
(1)进程0给进程1发i,同时用j 接收进程1的数据
(2)进程1给进程0发送i,同时用j 接收进程0的数据
最后的效果是,
进程0的j变量存的是进程1的i
进程1的j变量存的是进程0 的i如果你不用sendrecv 的话 每个case 里面要写两条(send,recv),还要注意顺序(标准消息传递不一定选择缓存发送模式,系统内存不足,可能会死锁),这就是sendrecv存在的意义。
[Fortran] 纯文本查看 复制代码
 program main
    include 'mpif.h'
    integer rank,ierr,status(mpi_status_size)
    integer i,j

    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world,rank,ierr)
    selectcase(rank)
    case(0)
    i=3
    j=5
    call mpi_sendrecv(i,1,mpi_integer,1,99,j,1,mpi_integer,1,99,mpi_comm_world,status,ierr)
    write(*,*)'myid=',rank,i,j
    case(1)
    i=4
    j=6
    call mpi_sendrecv(i,1,mpi_integer,0,99,j,1,mpi_integer,0,99,mpi_comm_world,status,ierr)
    write(*,*)'myid=',rank,i,j
    endselect
   
    write(*,1) rank,i,j
1  format(1x,'rank=',i3,'i=',i3,'j=',i3)
    call mpi_finalize(ierr)
    end



作者: bread31    时间: 2015-11-20 11:19
珊瑚虫 发表于 2015-11-20 11:14
不喜欢用if那就用select case 吧,下面的程序完成的工作是:
(1)进程0给进程1发i,同时用j 接收进程1的数 ...

可能我还是没明白sendrecv指令的用法……我先去看看您推荐的那本书,谢谢啦!
作者: 珊瑚虫    时间: 2015-11-20 11:29
就是说如果上面的程序没有用sendrecv 的话可以写成下面的形式(1),形式结果也是“对”的,但是不安全的,容易造成死锁, 而形式(2)是安全的不会造成“死锁”,
注意比较两种形式的区别
在比较复杂的情况下很难注意到这些细节,所以,MPI 帮你搞一个他自己去优化通信的形式就是sendrecv
形式(1)
[Fortran] 纯文本查看 复制代码
 program main
    include 'mpif.h'
    integer rank,ierr,status(mpi_status_size)
    integer i,j

    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world,rank,ierr)
    selectcase(rank)
    case(0)
    i=3
    j=5
    call mpi_send(i,1,mpi_integer,1,99,mpi_comm_world,ierr)
    call mpi_recv(j,1,mpi_integer,1,99,mpi_comm_world,status,ierr)
    write(*,*)'myid=',rank,i,j
    case(1)
    i=4
    j=6
    call mpi_send(i,1,mpi_integer,0,99,mpi_comm_world,ierr)            ! 注意此处的顺序和形式(2)不同
    call mpi_recv(j,1,mpi_integer,0,99,mpi_comm_world,status,ierr)  !注意此处的顺序和形式(2)不同
    write(*,*)'myid=',rank,i,j
    endselect
   
    write(*,1) rank,i,j
1  format(1x,'rank=',i3,'i=',i3,'j=',i3)
    call mpi_finalize(ierr)
    end

形式(2)
[Fortran] 纯文本查看 复制代码
 program main
    include 'mpif.h'
    integer rank,ierr,status(mpi_status_size)
    integer i,j

    call mpi_init(ierr)
    call mpi_comm_rank(mpi_comm_world,rank,ierr)
    selectcase(rank)
    case(0)
    i=3
    j=5
    call mpi_send(i,1,mpi_integer,1,99,mpi_comm_world,ierr)
    call mpi_recv(j,1,mpi_integer,1,99,mpi_comm_world,status,ierr)
    write(*,*)'myid=',rank,i,j
    case(1)
    i=4
    j=6
    call mpi_recv(j,1,mpi_integer,0,99,mpi_comm_world,status,ierr)
    call mpi_send(i,1,mpi_integer,0,99,mpi_comm_world,ierr)
    write(*,*)'myid=',rank,i,j
    endselect
   
    write(*,1) rank,i,j
1  format(1x,'rank=',i3,'i=',i3,'j=',i3)
    call mpi_finalize(ierr)
    end

作者: bread31    时间: 2015-11-20 12:04
珊瑚虫 发表于 2015-11-20 11:29
就是说如果上面的程序没有用sendrecv 的话可以写成下面的形式(1),形式结果也是“对”的,但是不安全的, ...

明白了,我是把sendrecv的意义给搞错了。谢谢指点!




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2