概述:本章中我们主要讨论使用MPI(一个可以被调用的函数库)进行分布式内存编程。
我们使用MPI来打印消息,选择一个进程作为输出进程,而其他进程先它发送要打印的消息。
这一小节里面主要还是完成MPI环境的安装以及运行一个最简单的MPI程序。
MPI_Init:调用此函数进行MPI系统所有必要的初始化设置。MPI_Finalize:告知MPI系统MPI已经使用完毕,可以释放资源了。
通信子:指一组可以互相发送消息的组合,用户启动的所有进程所组成的通信子成为MPI_COMM_WORLD,一个通信子中进程发送的消息不能被另一个通信子中进程接收。MPI_Comm_size用来获取通信子中的进程数。MPI_Comm_rank用来获取只能在调用进程在通信子中的进程号。
SPMD程序:在MPI中一般所有进程编译的都是相同的单个程序,不同在于根据程序中进程号不同而进入不同的分支采取不同的动作,所以MPI一般是SPMD程序。
通信
MPI_Send:共有6个参数,前三个指定发送的数据及类别,后三个数据指定接收方的进程号和动作以及通信子。
MPI_Recv:参数和send差不多,意义反过来,只不过还多了一个MPI_Status*的参数。
消息匹配:主要send和recv各个参数匹配消息就可以传递成功,而且有MPI_ANY_SOURCE和MPI_ANY_TAG两个通配符用来接收方适配任意发送方和标签。
在很多情况下我们使用通配符,即接收方不知道消息中的数据量,消息的发送者和消息的标签,这三个可以通过MPI_Status和MPI_Get_count得到。
MPI_Send和MPI_Recv的语义:一般来说,对于MPI_Send,其有一个截止大小,发送的消息小于截止大小将缓冲,大于截止大小将阻塞,而MPI_Recv一直是阻塞的直到收到消息,两者都有非阻塞的替代版本。使用这两个函数要格外消息,要确保send和recv是匹配的,否则可能造成进程一直悬挂。
串行梯形积分法:比较简单,直接看书。
使用foster方法来并行化梯形积分法,梯形划分越多则精度越高,注意区分程序中的全局变量和局部变量。
输出:因为竞争的存在,所以输出是不确定的,可以让0号进程依次接收要打印的消息来确定顺序。
输入:一般来说我们只允许0号进程能够使用stdin,并将数据发送给其他需要的进程。
概述:之前的程序我们让0号进程承担了太多工作,可以采用树形结构分担0号进程的工作,可以大大提高效率。在MPI中,设计通信子所有进程的通信成为集合通信,即一个函数就涉及了所有进程,而之前的send和recv是点对点通信。
MPI_Reduce:人工实现全局求和函数效率太低,MPI已经提供了相关接口实现,我们只需要调用即可,且还可以实现其他操作以及向量的操作,这就是一种集合通信。
集合通信与点对点通信:集合通信中,在通信子中的所有进程都必须调用相同的集合通信函数,且每个进程传递给MPI集合通信函数的参数必须是相容的。
MPI_Allreduce:之前那个函数只有目标进程能够获得最终结果,这个所有进程都能获得最终结果。
广播:我们也可以使用树形结构来完成输入数据的分发,在一个集合通信中,如果属于一个进程的数据被发送到通信子中所有进程则这样的集合通信成为广播。MPI也提供了相关的API MPI_Bcast
散射:有时候我们并不需要把所有数据发送给所有进程,而是把相应数据发送到相应进程,这个时候可以使用散射,所谓散射就是将数据的一部分发送给某个进程,然后把数据的另一部分发送给另一个进程,MPI为散射提供的API为MPI_Scatter,目前我们所学的这个函数值适用于块划分以及n可以整除comm_sz的情况。
聚集:刚刚说的两个函数比较偏发送,有时候我们需要把数据聚集到某个函数上,MPI提供的API叫做MPI_Gather。
全局聚集:全局聚集是MPI_Gather和MPI_Bcast的结合,即聚集每个进程的相应数据,并且使得每个进程都有聚集的数据。
概述:使用一条信息发送数据和使用多条信息发送等量数据,前者的效率高于后者,所以我们可以创建自己的数据类型来压缩要发送消息的条数。
派生数据类型的产生主要是通过存储数据的类型以及相应的偏移位置,可以使用MPI_Type_create_struct来产生派生数据类型,具体参数的定义见书。
使用前要用MPI_Get_address来获取地址,还要调用MPI_Type_commit初始化,生成成功后要广播给其他线程以让其他线程使用。
计时:可以使用MPI_Wtime来计时,串行程序可以使用宏GET_TIME,这两个都计算的是墙上时钟,即包含空闲等待时间。
前面说过MPI_Send有两种发送数据的方式,阻塞和非阻塞的,如果是阻塞的发送,容易造成死锁,例如所有线程都处于send,这样没有线程处于recv,死锁。所以MPI提供了一个MPI_Sendrecv,即发送一次消息并且接收一次消息。