MPI Send Recv 实现两种方式的树形结构

本文介绍了两种基于树形结构通信实现全局求和的方法。一种是每次寻找伙伴节点进行数据交换,另一种是按阶段将进程划分为发送方和接收方,直至所有数据汇总到根节点。这两种方法适用于 MPI 并行环境中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方式1:

每次寻找自己的partner,规定my_rank较小的接收,较大的发送。
// Function:   Global_sum
// Purpose:    Implement a global sum using tree-structured communication
// Notes:
// 1.  comm_sz must be a power of 2
// 2.  The return value is only valid on process 0
int Global_sum(int my_int, int my_rank, int comm_sz, MPI_Comm comm)
{
   // exp:np=4: 
   // @
   // 0  *                       bitmask=4
   // 0(2)  #      2(0)    #     bitmask=2
   // 0(1)  1(0)   2(3)   3(2)   bitmask=1
   int partner, recvtemp;
   int my_sum = my_int;
   unsigned bitmask = 1;
   
   while (bitmask < comm_sz) {
      partner = my_rank ^ bitmask;

      if (my_rank < partner) {
         MPI_Recv(&recvtemp, 1, MPI_INT, partner, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
         my_sum += recvtemp;
      } else {
         MPI_Send(&my_sum, 1, MPI_INT, partner, 2, MPI_COMM_WORLD);
         return 0; //发送任务完成,该进程结束执行
      }
      bitmask *= 2;
   }
   return my_sum;
}

方式2:

每次划分2大组,分为发送方和接收方,最终发送至P0
// Function:   Global_sum
// Purpose:    Implement a global sum using tree-structured communication
// Notes:
// 1.  comm_sz must be a power of 2
// 2.  The return value is only valid on process 0
int Global_sum(int my_int, int my_rank, int comm_sz, MPI_Comm comm)
{
   // exp np=4: 
   // @
   // *  *  |
   // #  #  |  #   #
   // 0  1  |  2   3
   // recv     send
   int dest, src;
   int recvtemp;
   int cur_comm_sz;
   int my_sum = my_int;

   cur_comm_sz = comm_sz;
   while (cur_comm_sz > 1 && my_rank < cur_comm_sz)
   {
      if (my_rank >= cur_comm_sz / 2) { //发送方
         dest = my_rank - cur_comm_sz / 2;
         MPI_Send(&my_sum, 1, MPI_INT, dest, 2, MPI_COMM_WORLD);
         return 0;  //发送完成就结束
      }
      else {
         src = my_rank + cur_comm_sz / 2;
         MPI_Recv(&recvtemp, 1, MPI_INT, src, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
         my_sum += recvtemp;
      }
      cur_comm_sz /= 2;
   }
   return my_sum;
}
在分布式内存环境下,如使用Message Passing Interface (MPI)进行并行计算,可以利用`MPI_Send`和`MPI_Recv`函数来实现矩阵相乘。这里以二维数组表示的矩阵为例,假设我们要在两个进程之间分别分配矩阵A和B,然后将它们相乘得到结果矩阵C。 首先,我们需要将矩阵A的行分发到每个接收进程,这称为“分布”(Distribution),通常通过循环遍历A的行,并使用`MPI_Send`发送给对应的列进程。同时,每个进程也要准备好接收来自其他进程的对应列数据。 ```cpp // 假设 A[row][col] 是矩阵A的一个元素 for (int i = 0; i < rows_A; i++) { for (int j = 0; j < cols_B; j++) { MPI_Send(&A[i][j], 1, MPI_DOUBLE, col_to_send[j], i * cols_B, MPI_COMM_WORLD); } } ``` 接着,每个进程接收到所有列的数据后,开始计算局部的子矩阵乘法部分,即把接收到的矩阵B的列与本进程中属于A的部分行相乘,然后将结果累加到本地结果矩阵C上。这个过程通常是同步的,因为需要等待所有的数据到达才能进行下一步计算。 ```cpp // 假设 C[row][col] 是矩阵C的一个元素 double local_C[row][cols_B]; for (int k = 0; k < cols_A; k++) { for (int i = 0; i < row; i++) { double sum = 0; for (int j = 0; j < cols_B; j++) { sum += local_data[k][i] * received_data[j][k]; // local_data是本地存储的B列 } local_C[i][k] = sum; } } // 累加到全局矩阵C MPI_Reduce(local_C, &global_C[my_row][my_col], row, MPI_DOUBLE, MPI_SUM, my_col, MPI_COMM_WORLD); ``` 最后,如果使用的是非对称模式(如环形通信),可能还需要进行一次反向通信来交换数据,以便完成整个矩阵C的构建。完成后,每个进程拥有C的一部分,需要通过`MPI_Irecv`和`MPI_Waitall`等异步操作获取所有结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值