MPI_Send
是 MPI 中用于发送消息的基本函数。它提供了点对点通信的一种方式,允许一个进程发送数据到另一个进程。使用 MPI_Send
可以将某个进程中的数据发送到另一个进程指定的缓冲区。
MPI_Send
函数原型:
int MPI_Send(
const void *buf, // 发送缓冲区起始地址
int count, // 发送数据的个数
MPI_Datatype datatype, // 发送数据的类型
int dest, // 接收数据的进程编号(目标进程的rank)
int tag, // 消息标识符
MPI_Comm comm // 通信域
);
参数解释:
-
*
buf
(const void)**:发送数据缓冲区的指针,表示要发送数据的起始地址。它指向存储要发送数据的内存区域。- 例如,如果发送一个整数数组,可以传递数组的起始地址。
int data[10];
MPI_Send(data, 10, MPI_INT, dest, tag, comm);
-
count
(int):要发送的数据个数,表示buf
中有多少个数据元素需要发送。这个值与datatype
的大小有关。例如,如果datatype
是MPI_INT
,而count
是 10,则表示发送 10 个整数。 -
datatype
(MPI_Datatype):发送的数据类型,用于指定缓冲区中元素的数据类型。MPI 提供了一些常用的预定义数据类型:MPI_INT
:用于发送整型数据(例如int
)。MPI_FLOAT
:用于发送单精度浮点数(例如float
)。MPI_DOUBLE
:用于发送双精度浮点数(例如double
)。- 还可以创建自定义的数据类型。
-
dest
(int):目标进程的rank
,即接收数据的进程的编号。rank
是指在通信域comm
中,每个进程的唯一标识符(编号)。如果你要将数据发送给进程 3,则dest = 3
。 -
tag
(int):消息标识符,用户自定义的整数,用于区分不同的消息。例如,你可以使用不同的tag
值来区分多个并发的发送操作。发送和接收的tag
值必须匹配,接收进程才能正确接收消息。 -
comm
(MPI_Comm):通信域,定义进程之间的通信范围。常见的通信域是MPI_COMM_WORLD
,它包括了所有在 MPI 初始化时启动的进程。也可以使用自定义通信域。
MPI_Send
的工作机制
-
MPI_Send
是一个 阻塞 的发送函数,这意味着在调用该函数时,发送进程会等待,直到它的发送缓冲区可以重用(即,数据已经复制到系统缓冲区,或直接发送给接收进程)。这个等待时间取决于通信的实现方式,但对程序透明。 -
如果接收端没有准备好接收消息,
MPI_Send
可能会导致发送端等待,直到接收端调用MPI_Recv
。
例子
以下是一个简单的 MPI_Send
的使用示例:
#include "mpi.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
int myid, numprocs, dest, source, tag = 0;
int send_data, recv_data;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
if (myid == 0) {
// 进程 0 发送数据
send_data = 42;
dest = 1;
MPI_Send(&send_data, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
printf("Process %d sent data %d to process %d\n", myid, send_data, dest);
} else if (myid == 1) {
// 进程 1 接收数据
source = 0;
MPI_Recv(&recv_data, 1, MPI_INT, source, tag, MPI_COMM_WORLD, &status);
printf("Process %d received data %d from process %d\n", myid, recv_data, source);
}
MPI_Finalize();
return 0;
}
输出示例:
Process 0 sent data 42 to process 1
Process 1 received data 42 from process 0
常见使用场景
-
点对点通信:
MPI_Send
常用于两个进程之间传递数据,比如在分布式计算中,主进程将任务分发给工作进程,或者工作进程将结果返回给主进程。 -
边界交换:在并行计算中,常需要在不同进程之间交换边界数据,比如在网格计算中,你可以通过
MPI_Send
将一个子网格的边界发送给相邻的进程。
MPI_Send
与其他发送函数的区别
MPI_Send
(阻塞发送):会阻塞进程,直到消息发送完毕。MPI_Isend
(非阻塞发送):消息发送是异步的,进程不会等待发送完成,立即返回并继续执行。MPI_Ssend
(同步发送):发送方会等待接收方确实已经开始接收,才能完成发送。