MPI_Isend & MPI_Send 创建临时通信句柄
在前面的文章中举了例子,我们使用MPI_Isend接口发送数据时,有个传出参数request,该参数是创建的通信句柄,
实际上该句柄是一个临时句柄,即只用于一次性发送数据的场景,如不能在循环体中多次使用:
int main(int argc, char *argv[])
{
int err = MPI_Init(&argc,&argv);
int rank,size;
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int data = 100;
//将在发送进程的MPI_Isend创建初始化,数据接收进程中使用该句柄
MPI_Request request;
MPI_Status status;
if(rank > 0)
{
MPI_Irecv(&data,1,MPI_INT,rank-1,0,MPI_COMM_WORLD,&request);
std::cout << "rank = " << rank << " recived data is : " << data << std::endl;
MPI_Wait(&request, &status);
std::cout << "rank = " << rank << " recived data is : " << data << std::endl;
}
if(rank < size - 1)
{
data = rank;
MPI_Isend(&data,1,MPI_INT, (rank + 1)%size, 0 ,MPI_COMM_WORLD, &request);
MPI_Wait(&request, &status);
}
err = MPI_Finalize();
return 0;
}
一个多次使用临时通信句柄的错误案例
//错误案例
MPI_Request request;
MPI_Status status;
int buf[100];
for (int i = 0; i < 10; i++) {
MPI_Recv(buf, 100, MPI_INT, 0, 0, MPI_COMM_WORLD, &status, &request);
// 这里可能会出现 MPI_ERR_REQUEST 错误
}
//如果要多次使用临时句柄,那就要多个临时句柄
MPI_Request requests[10];
MPI_Status statuses[10];
int buf[10][100];
for (int i = 0; i < 10; i++) {
MPI_Recv(buf[i], 100, MPI_INT, 0, 0, MPI_COMM_WORLD, &statuses[i], &requests[i]);
}
MPI_Waitall(10, requests, statuses);
MPI_Send_init 创建持久性句柄
int MPI_Send_init(const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm, MPI_Request *request)
- buf:void* 类型,发送缓冲区起始地址;
- count:int 类型,发送缓冲区中元素的个数;
- datatype:MPI_Datatype 类型,发送元素的 MPI 数据类型;
- dest:int 类型,接收消息的进程编号;
- tag:int 类型,消息标识;
- comm:MPI_Comm 类型,消息通信域;
- request:MPI_Request* 类型,通信请求句柄(持久化)。
使用该接口生成的持久化句柄,需要使用专用接口进行资源释放MPI_Request_free()
代码使用案例
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
int size, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
//发送操作的缓冲区和发送目标
int send_data = rank;
int dest = (rank + 1) % size;
//创建持久化通信请求句柄
MPI_Request request;
MPI_Send_init(&send_data, 1, MPI_INT, dest, 0, MPI_COMM_WORLD, &request);
//可以重复的使用该句柄,前提是重复相同的数据,如果不同,则创建使用临时句柄
for (int i = 0; i < size; i++) {
//启动发送消息
MPI_Start(&request);
printf("Rank %d is sending data to Rank %d\n", rank, dest);
//等待发送完成
MPI_Wait(&request, MPI_STATUS_IGNORE);
printf("Rank %d has sent data to Rank %d\n", rank, dest);
}
//释放持久化通信请求句柄
MPI_Request_free(&request);
MPI_Finalize();
return 0;
}
临时句柄和持久性句柄的选择
- 多次循环发送不同的数据必须使用临时句柄
- 如果多次发送的数据是一样的,那么就可以使用持久化的句柄。