使用 MPI_Isend() MPI_and Irecv() 时,是否应该使用相同的请求?如果消息已经是一个数组,应该如何传递?

when using MPI_Isend() MPI_and Irecv(), should the pair use the same request? in case the message is already an array, how it should be passed?

在这段代码中,我尝试使用非阻塞发送和接收作为练习进行广播。我有很多问题。 1.Should 我将 Isend() 和 Irecv() 配对使用相同的请求? 2.When消息是一个数组,应该如何传递?在这种情况下,消息或消息? 3.Why 我不能在少于或多于 8 个处理器上 运行 此代码?如果排名不退出,它不应该继续执行而不执行那段代码吗? 4.The 底部的片段是为了一次打印总时间,但 waitall() 不起作用,我不明白为什么。 5. 当传递长于 2^12 的数组时,我得到分段错误,而我已经检查了 Isend() 和 Irecv() 的限制,它们应该处理更大长度的消息。 6.I 使用 long double 来记录时间,这是一种常见的做法还是好的做法?当我使用像 float 或 double 这样的小变量时,我会得到 nan。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<mpi.h>

int main(int argc, char *argv[]){

  MPI_Init(&argc, &argv);
  int i, rank, size, ready;
  long int N = pow(2, 10);
  float* message = (float *)malloc(sizeof(float *) * N + 1);
  long double start, end;

  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  //MPI_Request* request = (MPI_Request *)malloc(sizeof(MPI_Request *) * size);
  MPI_Request request[size-1];
/*Stage I: -np 8*/
  if(rank == 0){
    for(i = 0; i < N; i++){
      message[i] = N*rand();
      message[i] /= rand();
      }
    start = MPI_Wtime();
    MPI_Isend(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[0]);
    MPI_Isend(&message, N, MPI_FLOAT, 2, 0, MPI_COMM_WORLD, &request[1]);
    MPI_Isend(&message, N, MPI_FLOAT, 4, 0, MPI_COMM_WORLD, &request[3]);
    printf("Processor root-rank %d- sent the message...\n", rank);
  }
  if (rank == 1){
    MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[0]);
    MPI_Wait(&request[0], MPI_STATUS_IGNORE);
    printf("Processor rank 1 received the message.\n");
    MPI_Isend(&message, N, MPI_FLOAT, 3, 0, MPI_COMM_WORLD, &request[2]);
    MPI_Isend(&message, N, MPI_FLOAT, 5, 0, MPI_COMM_WORLD, &request[4]);

  }
  if(rank == 2){
    MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[1]);
    MPI_Wait(&request[1], MPI_STATUS_IGNORE);
    printf("Processor rank 2 received the message.\n");
    MPI_Isend(&message, N, MPI_FLOAT, 6, 0, MPI_COMM_WORLD, &request[5]);
  }
  if(rank == 3){
    MPI_Irecv(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[2]);
    MPI_Wait(&request[2], MPI_STATUS_IGNORE);
    printf("Processor rank 3 received the message.\n");
    MPI_Isend(&message, N, MPI_FLOAT, 7, 0, MPI_COMM_WORLD, &request[6]);
  }
  if(rank == 4){
    MPI_Irecv(&message, N, MPI_FLOAT, 0, 0, MPI_COMM_WORLD, &request[3]);
    MPI_Wait(&request[3], MPI_STATUS_IGNORE);
    printf("Processor rank 4 received the message.\n");
  }
  if(rank == 5){
    MPI_Irecv(&message, N, MPI_FLOAT, 1, 0, MPI_COMM_WORLD, &request[4]);
    MPI_Wait(&request[4], MPI_STATUS_IGNORE);
    printf("Processor rank 5 received the message.\n");
  }
  if(rank == 6){
    MPI_Irecv(&message, N, MPI_FLOAT, 2, 0, MPI_COMM_WORLD, &request[5]);
    MPI_Wait(&request[5], MPI_STATUS_IGNORE);
    printf("Processor rank 6 received the message.\n");
  }
  if(rank == 7){
    MPI_Irecv(&message, N, MPI_FLOAT, 3, 0, MPI_COMM_WORLD, &request[6]);
    MPI_Wait(&request[6], MPI_STATUS_IGNORE);
    printf("Processor rank 7 received the message.\n");
  }
  /*MPI_Testall(size-1,request,&ready, MPI_STATUS_IGNORE);*/
/*  if (ready){*/
    end = MPI_Wtime();
    printf("Total Time: %Lf\n", end - start);
/*}*/

  MPI_Finalize();
}
  1. 每个 MPI 任务 运行 在其自己的地址 space 中,因此 request[1] 排名 0request[1] 排名之间没有相关性2。这意味着您不必“配对”请求。也就是说,如果您认为“配对”请求可以提高代码的可读性,即使这不是必需的,您也可能想要这样做。
  2. MPI_Isend()MPI_Irecv()的buffer参数是指向数据开始的指针,这是message(而不是 &message) 在这里。
  3. 如果你 运行 假设有 2 个 MPI 任务,排名 0 上的 MPI_Send(..., dest=2, ...) 将失败,因为 2 是 [=21= 中的无效排名] 通讯器.
  4. 许多请求在调用 MPI_Waitall()(这里是 MPI_Testall())时未初始化。一种选择是首先将它们全部初始化为 MPI_REQUEST_NULL.
  5. 使用 &message 导致内存损坏,这可能解释了崩溃。
  6. 根据 MPI 标准,原型是 double MPI_Wtime(),因此您宁愿在此处使用 double(NaN 可能来自上述内存损坏)