发送与接收
发送和接收是 MPI 里面两个基础的概念,接下来介绍 MPI 的同步(或阻塞, blocking)发送和接收方法。
MPI 的发送和接收方法是按以下方式进行的:开始的时候,A 进程决定要发送一些消息给 B 进程。A进程就会把需要发送给B进程的所有数据打包好,放到一个缓存里面。
所有数据会被打包到一个大的信息里面,因此缓存常常会被比作信封
数据打包进缓存之后,通信设备(通常是网络)就需要负责把信息传递到正确的地方。这个正确的地方也就是根据特定秩确定的那个进程。
尽管数据已经被送达到 B 了,但是进程 B 依然需要确认它想要接收 A 的数据。一旦它确定了这点,数据就被传输成功了。进程 A 会接收到数据传递成功的信息,然后去干其他事情。
MPI 方法
MPI_Send(
void* data,
int count,
MPI_Datatype datatype,
int destination,
int tag,
MPI_Comm communicator)
MPI_Recv(
void* data,
int count,
MPI_Datatype datatype,
int source,
int tag,
MPI_Comm communicator,
MPI_Status* status)
方法定义是类似的。第一个参数是数据缓存。第二个和第三个参数分别描述了数据的数量和类型。MPI_send
会精确地发送 count 指定的数量个元素,MPI_Recv
会最多接受 count 个元素。第四个和第五个参数指定了发送方/接受方进程的秩以及信息的标签。第六个参数指定了使用的 communicator。MPI_Recv
方法特有的最后一个参数提供了接受到的信息的状态。
基础 MPI 数据结构
举例来说,如果一个进程想要发送一个整数给另一个进程,它会指定 count 为 1,数据结构为 MPI_INT
。默认的 MPI 数据结构以及它们在 C 语言里对应的结构如下:
MPI datatype | C equivalent |
---|---|
MPI_SHORT | short int |
MPI_INT | int |
MPI_LONG | long int |
MPI_LONG_LONG | long long int |
MPI_UNSIGNED_CHAR | unsigned char |
MPI_UNSIGNED_SHORT | unsigned short int |
MPI_UNSIGNED | unsigned int |
MPI_UNSIGNED_LONG | unsigned long int |
MPI_UNSIGNED_LONG_LONG | unsigned long long int |
MPI_FLOAT | float |
MPI_DOUBLE | double |
MPI_LONG_DOUBLE | long double |
MPI_BYTE | char |
之后可以创建自己的 MPI 数据类型来构建更复杂的消息类型
Send-Recv (发送-接收程序)
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
MPI_Init(NULL, NULL);
// 得到当前进程的 rank 以及整个 communicator 的大小
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD,