Fortran Coder

查看: 10727|回复: 8
打印 上一主题 下一主题

[并行] 刚接触fortran和mpi,求助mpi_sendrecv的问题

[复制链接]

7

帖子

2

主题

0

精华

入门

混子

F 币
122 元
贡献
53 点

规矩勋章

QQ
跳转到指定楼层
楼主
发表于 2015-11-20 10:28:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、在不使用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
另外求大师推荐几本合适的书,方便初学者自学。谢谢大家!

分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

135

帖子

15

主题

0

精华

版主

F 币
1159 元
贡献
637 点

爱心勋章管理勋章

沙发
发表于 2015-11-20 10:51:41 | 只看该作者
(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 但是每个进程执行的发送目标和接收目标都是相同的,本身接收和发送的就和上面一样不匹配,所以程序一直卡着不往下走。

评分

参与人数 1F 币 +9 贡献 +9 收起 理由
fcode + 9 + 9

查看全部评分

7

帖子

2

主题

0

精华

入门

混子

F 币
122 元
贡献
53 点

规矩勋章

QQ
板凳
 楼主| 发表于 2015-11-20 10:57:26 | 只看该作者
珊瑚虫 发表于 2015-11-20 10:51
(1) 新手推荐都志辉的书《高性能计算之并行编程技术-MPI并行程序设计》 百度很容易下到
(2) 第一个程序 ...

非常感谢!第一个程序我理解问题所在了,但是第二个的问题通常都是怎么解决的啊,send和recv在同一个指令里,也没法用if呀……

135

帖子

15

主题

0

精华

版主

F 币
1159 元
贡献
637 点

爱心勋章管理勋章

地板
发表于 2015-11-20 10:59:31 | 只看该作者
bread31 发表于 2015-11-20 10:57
非常感谢!第一个程序我理解问题所在了,但是第二个的问题通常都是怎么解决的啊,send和recv在同一个指令 ...

要看你实现什么样的功能,请先说清楚你要实现的功能。

7

帖子

2

主题

0

精华

入门

混子

F 币
122 元
贡献
53 点

规矩勋章

QQ
5#
 楼主| 发表于 2015-11-20 11:04:14 | 只看该作者
珊瑚虫 发表于 2015-11-20 10:59
要看你实现什么样的功能,请先说清楚你要实现的功能。

初学者试指令,只是想实现把0的i发送给1的j……

135

帖子

15

主题

0

精华

版主

F 币
1159 元
贡献
637 点

爱心勋章管理勋章

6#
发表于 2015-11-20 11:14:28 | 只看该作者
本帖最后由 珊瑚虫 于 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


评分

参与人数 1贡献 +9 收起 理由
楚香饭 + 9

查看全部评分

7

帖子

2

主题

0

精华

入门

混子

F 币
122 元
贡献
53 点

规矩勋章

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

可能我还是没明白sendrecv指令的用法……我先去看看您推荐的那本书,谢谢啦!

135

帖子

15

主题

0

精华

版主

F 币
1159 元
贡献
637 点

爱心勋章管理勋章

8#
发表于 2015-11-20 11:29:10 | 只看该作者
就是说如果上面的程序没有用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

7

帖子

2

主题

0

精华

入门

混子

F 币
122 元
贡献
53 点

规矩勋章

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

明白了,我是把sendrecv的意义给搞错了。谢谢指点!
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-12-26 10:04

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表