使用MPI_Send/MPI_Recv替代MPI_Gather时根进程缓冲区未更新问题
核心问题定位
运行结果和预期不符的根本原因是接收逻辑的内存写入位置错误,和MPI基础收发接口无关:
- 根进程的
MPI_Recv每次都从single_arr的起始地址开始写入数据,没有按照进程编号做内存偏移,导致每接收一个进程的数据集,就会把之前写入的内容完全覆盖,根本没有按块存储不同进程的发送内容 - 这种写法下,根进程的
single_arr只有开头两个元素会被最后一次接收的进程数据覆盖,其余位置都是vector默认初始化的0值。当启动4个进程时,最后一次接收操作是收取rank3的数据集,写入缓冲区开头,这也是你看到输出前两个值为3、4,其余全为0的直接原因。
代码调整方案
只需要修改根进程的接收循环逻辑,让每个进程的数据集写入到对应的缓冲区位置,整体布局和MPI_Gather的默认内存规则保持一致,不需要改动其他流程:
- 按照
MPI_Gather的标准布局约定:第p个进程的N个元素,在根进程的接收缓冲区中的起始偏移为p * N - 接收i号进程的数据时,把接收指针从
single_arr.data()调整为single_arr.data() + i * N,避免反复覆盖开头的内容 - 原代码中从未被使用的
receive_data变量可以直接删除,不影响运行逻辑
修改后的根进程接收段代码如下:
if (rank == root) { for (int i = 1; i < size; i++) { // 定位到当前进程对应的缓冲区写入位置 int* write_pos = single_arr.data() + i * N; MPI_Recv(write_pos, N, MPI_INT, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } }
调整后的运行效果
当进程数为4、N=2时,根进程的接收缓冲区存储内容会和预期完全匹配:
- 偏移0、1:根进程自己的x数组值
0, 1 - 偏移2、3:rank1发送的x数组值
1, 2 - 偏移4、5:rank2发送的x数组值
2, 3 - 偏移6、7:rank3发送的x数组值
3, 4
拼接后的完整输出和你期望的顺序完全一致,结果和直接调用MPI_Gather没有任何差异。
内容的提问来源于stack exchange,提问作者MA19
相关产品推荐
相关产品推荐

