MPI入门笔记

MPI入门笔记

本文是 https://zhuanlan.zhihu.com/p/355652501 学习时的笔记。

常用函数

MPI_Init(&argc,&argv)
mpi程序书写时需要必须写在前面的第一行mpi代码(不需要是整个程序的第一行,但一定是有关mpi代码的第一行),MPI_Finalize() mpi程序书写时需要必须写的最后一行mpi代码

MPI_COMM_rank(MPI_Comm,int *rank)
返回当前进程号,通过传入的rank返回进程号。MPI_Comm是指通信域(community),和进程之间通信有关。

MPI_COMM_Size(MPI_Comm,int *size)
返回该通信域内的进程数量。如果传入的MPI_Comm是MP_COMM_WORLD,则获取总进程数。

MPI_Send(type * buf,int count,MPI_Datatype,int dest,int tag,MPI_Comm comm)
发送函数,用于进程间发送数据。
buf是存储数据的空间的首地址count是长度,指buf之后多少个数据
MPI_Datatype指传递的MPI数据类型,如MPI_INT,其他都是这个范式。
dest指对应的数据接收进程的编号tag指这次数据传递的编号,以保证多个传递过程的数据接收不混乱MPI_Comm是指通信域

MPI_Recv(type * buf,int count,MPI_Datatype,int source,int tag,MPI_Comm comm,MPI_Status *status)
和MPI_Send配套使用。
source表明从哪个进程接收东西
status用于返回数据交换的结果,数据类型为MPI_Status,有status.MPI_SOURCE,status.MPI_TAG和status.MPI_ERROR三种信息类型,库的包中又定义,直接调用就是。
其他与send一样。

MPI_Reduce(&mypi,&pi,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD)
此为规约操作,将MPI_COMM_WORLD通信域中的各个进程中类型为MPI_DOUBLE的叫mypi的变量发送到缓存区并执行MPI_SUM操作,并将求和结果存入进程0的叫pi的变量中。
mpicc -o pi.exe pi.c
mpicc是c的编译指令。将pi.c编译成pi.exe。
mpicxx -o pi.exe pi.cpp
mpicxx是c++的编译指令。
mpirun -np 6 pi.exe
mpirun是mpi的运行指令,-np指定以多少个线程来运行程序。mpi以6个线程运行pi.exe线程。

练手代码

#include "mpi.h" 
#include "time.h" 
#include <stdio.h> 
double f(double); 
double f(double x) {
         return (4.0/(x*x+1.0)); 
 } 
int main(int argc,char *argv[]){
         clock_t start,stop;
         start = clock();
         MPI_Init(&argc,&argv);         i
         nt myid,numprocs;         
         double mypi,finalpi;         
         MPI_Comm_size(MPI_COMM_WORLD,&numprocs);         
         MPI_Comm_rank(MPI_COMM_WORLD,&myid);//myid从0开始        
         printf("Process %d of %d\n",myid,numprocs);         
         long n=100000000;//将x轴分为100份       
         double h=1.0/(double)n;         
         for(long i =myid+1;i<=n;i+=numprocs){                 
         mypi += f(((double)i-0.5)*h);         
         }         
         mypi = mypi*h;         
         MPI_Reduce(&mypi,&finalpi,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);         
         if(myid == 0){
                         stop = clock(); 
                         printf("The lasting time is %.10f. \n",((double)(stop-start))/CLOCK_TAI);                
                         printf("Finally,the pi is %.10f. \n",finalpi);         
                         }        
         MPI_Finalize();
         return 0;
         }

在尝试之后发现,符合直觉的是,并非线程越多越好。这里面影响因素可能很多,如cpu核数,cpu支持的线程数等。最佳加速效果大概率是一个适中的值,在没有好的判断方法的情况下,只能去试。

两种基本的并行程序设计模式:对等模式 和 主从模式

对等模式

简单来说就是,所有进程之间逻辑地位都是平等的,不需要在运行结束后或则在运行某一阶段将数据
由其中一个进程(此进程担当主进程)。事实上也不必太过在意模式的规定,进程间相对平等就是,并非说对等模式下进程间就不能将数据汇总到一个进程中。

死锁和内存溢出
MPI通信分为阻塞通信和非阻塞通信。阻塞与非阻塞,很简单,就是说在进行通信是(发送或接收的其中一个)程序会卡在通信语句处,等通信完成再往下运行。阻塞通信如果收发匹配不当,会造成死锁,比如两个进程都在接受或发送。
另外,MPI_SEND和MPI_RECV都是采用MPI的是标准通信模式,即是否对发送的数据进行缓存不是由程序员决定,而是由MPI决定的。若两个进程都在发送数据,数据都存往缓冲区,这就会造成内存的溢出

捆绑发送接收
前面提到了死锁,程序员为了避免死锁需要复杂的操作,但还是容易出现问题。MPI提供了简单的解决方案,即捆绑发送接收–MPI_SENDRECV。其将发送方和接收方的数据在一个函数中声明清楚,这样就免去了一些不必要的麻烦。

虚拟进程
MPI_PROC_NULL就是所谓的虚拟进程。它可以用来简化代码逻辑。比如:程序中总会出现一些特殊情况,其大多是在数据的边缘,数据中间部分所存在的规律到这儿不适用了,需要程序员在编写代码时对其进行单独处理,很是让人头疼。而虚拟进程就是来补在边缘部分后面,使其还满足之前的规律。

主从模式

每太看懂,简单说就是有个主进程,其他都是从进程。作者用fortran写的代码,还感觉写的不是很仔细,我自己也比较烦躁,没怎么看懂。

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值