MPI学习二 MPI并行程序的两种基本模式

本文介绍了MPI并行程序设计的两种基本模式:对等模式和主从模式。对等模式中,通过Jacobi迭代算法进行示范,详细阐述了数据划分和通信方式。主从模式则通过矩阵向量乘法的例子,展示了如何利用广播、发送接收数据进行计算和结果收集。文中包含实际运行示例,展示了MPI并行计算的效率。
摘要由CSDN通过智能技术生成

       MPI的两种最基本的并行程序设计模式 即对等模式和主从模式。 
  对等模式:各个部分地位相同,功能和代码基本一致,只不过是处理的数据或对象不同,也容易用同样的程序来实现。 
  主从模式:分为主进程和从进程,程序通信进程之间的一种主从或依赖关系 。MPI程序包括两套代码,主进程运行其中一套代码,从进程运行另一套代码。

1. 对等模式MPI程序设计

1.1 Jacobi 迭代

  一句话概括就是矩阵每个元素都是其上下左右四个元素的平均值,矩阵四个边界的值不变。

1.2 用MPI程序实现Jacobi 迭代

  将参加迭代的数据按列进行分割 并假设一共有4个进程同时并行计算。 

  假设需要迭代的数据是 M*M 的二维数组 A(M-1,M-1),令 M=4*N,按图示进行数据划分,则分布在四个不同进程上的数据分别是,

进程0:A(M-1, 0 : N-1) 
进程1:A(M-1, N : 2*N-1) 
进程2:A(M-1, 2*N : 3*N-1) 
进程3:A(M-1, 3*N : M-1)

  由于在迭代过程中,边界点新值的计算需要相邻边界其它块的数据,因此在每一个数据块的两侧又各增加1列的数据空间,用于存放从相邻数据块通信得到的数据。这样原来每个数据块的大小从 M*N 扩大到 M*N+2,进程0和进程1的数据块只需扩大一块即可满足通信的要求, 但这里为了编程的方便和形式的一致,在两边都增加了数据块。 

  计算和通信过程: 
   1. 对数组赋初值,边界赋为8,内部赋为0。 
   2. 每个进程都需要从相邻的进程得到数据块,同时每一个进程也都需要向相邻的进程提供数据块。注意:通信次序保证进程之间不会出现死锁。 
   3. 进行Jacobi迭代。

 
 
 
  1. #include "mpi.h"
  2. #include <stdio.h>
  3. #define totalsize 16
  4. #define mysize totalsize/4
  5. #define steps 10
  6. void main(int argc,char* argv[])
  7. {
  8. int myid,numprocs,n,i,j,rc;
  9. float a[totalsize][mysize+2];
  10. float b[totalsize][mysize+2]; //临时数组用来记录临时得到的新值
  11. float temp[totalsize]; //进程间通信得到的数据
  12. int begin_col,end_col,ierr;
  13. MPI_Status status;
  14. MPI_Init(&argc,&argv);
  15. MPI_Comm_rank(MPI_COMM_WORLD,&myid);
  16. MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
  17. fprintf(stderr,"Process %d of %d is alive.\n",myid,numprocs);
  18. //初始化
  19. for(j=0;j<mysize+2;j++)
  20. for(i=0;i<totalsize;i++)
  21. a[i][j]=0.0;
  22. if(myid==0)
  23. for(i=0;i<totalsize;i++)
  24. a[i][1]=8.0;
  25. if(myid==3)
  26. for(i=0;i<totalsize;i++)
  27. a[i][mysize]=8.0;
  28. for(i=1;i<mysize+1;i++)
  29. {
  30. a[0][i]=8.0;
  31. a[totalsize-1][i]=8.0;
  32. }
  33. //Jacobi 迭代
  34. for(n=1;n<=steps;n++)
  35. {
  36. //从右侧邻居得到数据
  37. if(myid<3)
  38. {
  39. MPI_Recv(&temp[0],totalsize,MPI_FLOAT,myid+1,10,MPI_COMM_WORLD,&status);
  40. for(i=0;i<totalsize;i++)
  41. a[i][mysize+1]=temp[i];
  42. }
  43. //向左侧邻居发送数据
  44. if(myid>0)
  45. {
  46. for(i=0;i<totalsize;i++)
  47. temp[i]=a[i][1];
  48. MPI_Send(&temp[0],totalsize,MPI_FLOAT,myid-1,10,MPI_COMM_WORLD);
  49. }
  50. //向右侧邻居发送数据
  51. if(myid<3)
  52. {
  53. for(i=0;i<totalsize;i++)
  54. temp[i]=a[i][mysize];
  55. MPI_Send(&temp[0],totalsize,MPI_FLOAT,myid+1,10,MPI_COMM_WORLD);
  56. }
  57. //从左侧邻居得到数据
  58. if(myid>0)
  59. {
  60. MPI_Recv(&temp[0],totalsize,MPI_FLOAT,myid-1,10,MPI_COMM_WORLD,&status);
  61. for(i=0;i<totalsize;i++)
  62. a[i][0]=temp[i];
  63. }
  64. begin_col=1;
  65. end_col=mysize;
  66. if(myid==0)
  67. begin_col=2;
  68. if(myid==3)
  69. end_col=mysize-1;
  70. for(j=begin_col;j<=end_col;j++)
  71. for(i=1;i<totalsize-1;i++)
  72. b[i][j]=0.25*(a[i][j+1]+a[i][j-1]+a[i+1][j]+a[i-1][j]);
  73. for(j=begin_col;j<=end_col;j++)
  74. for(i=1;i<totalsize-1;i++)
  75. a[i][j]=b[i][j]; //一次迭代完成后,统一进行更新
  76. }
  77. MPI_Barrier(MPI_COMM_WORLD);
  78. fprintf(stderr,"\nProcess %d :\n",myid);
  79. begin_col=1;
  80. end_col=mysize;
  81. for(i=0;i<totalsize;i++)
  82. {
  83. for(j=begin_col;j<=end_col;j++)
  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值