MPI C/C++中CSR稀疏矩阵行数组的指定区间分块共享咨询
MPI C/C++ 实现CSR行数组的拆分方案
针对你提到的数组共享需求——全局int array[10](CSR行指针数组),3个进程分别获取array[0:3](含3)、array[3:6](含6)、array[6:9](含9),我给你整理了两种常用的实现方式,都是MPI标准库中的方法,适配CSR稀疏矩阵的并行处理场景。
一、核心思路说明
先明确每个进程需要的片段细节:
- 进程0(rank=0):索引0~3,共4个元素
- 进程1(rank=1):索引3~6,共4个元素
- 进程2(rank=2):索引6~9,共4个元素
这里的片段重叠(比如array[3]同时属于进程0和1)是合理的——在CSR并行处理中,后续进程需要知道自己负责行的起始偏移量,所以共享这个边界值是必要的。
二、推荐实现:使用MPI_Scatterv(分散发送)
MPI_Scatterv是MPI_Scatter的扩展,支持向不同进程发送不同长度/起始位置的数据块,非常适合这种每个进程接收元素数量相同但起始偏移不同的场景,代码更简洁高效。
完整代码示例
#include <mpi.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); int rank, size; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); // 确保运行时恰好有3个进程,匹配需求 if (size != 3) { if (rank == 0) { printf("This program requires exactly 3 processes!\n"); } MPI_Finalize(); return 1; } int* global_array = NULL; int local_size = 4; // 每个进程的本地数组大小都是4 int* local_array = (int*)malloc(local_size * sizeof(int)); if (!local_array) { printf("Rank %d: Memory allocation failed!\n", rank); MPI_Abort(MPI_COMM_WORLD, 1); } if (rank == 0) { // 主进程初始化全局CSR行数组(示例值,实际替换为你的行指针数据) global_array = (int*)malloc(10 * sizeof(int)); for (int i = 0; i < 10; i++) { global_array[i] = i * 2; } } // 定义发送计数和位移数组(主进程用于指定每个进程的接收范围) int sendcounts[3] = {4, 4, 4}; int displs[3] = {0, 3, 6}; // 分散发送全局数组到各个进程 MPI_Scatterv(global_array, sendcounts, displs, MPI_INT, local_array, local_size, MPI_INT, 0, MPI_COMM_WORLD); // 验证每个进程的本地数组是否正确 printf("Rank %d: Local array elements: ", rank); for (int i = 0; i < local_size; i++) { printf("%d ", local_array[i]); } printf("\n"); // 释放内存 if (rank == 0) { free(global_array); } free(local_array); MPI_Finalize(); return 0; }
代码关键解释
- 进程合法性检查:先确保运行时进程数为3,避免不符合需求的执行。
- 数组分配:主进程负责初始化全局行数组,所有进程根据需求分配本地数组内存。
MPI_Scatterv参数:sendcounts:指定每个进程接收的元素数量(这里都是4)displs:指定每个进程接收数据在全局数组中的起始索引(0、3、6)- 最后一个参数
0表示主进程作为数据发送源
三、备选方案:手动MPI_Send/MPI_Recv
如果需要更精细的调试或特殊控制逻辑,也可以手动实现发送接收,适合自定义场景:
#include <mpi.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); int rank, size; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); if (size != 3) { if (rank == 0) printf("Need exactly 3 processes!\n"); MPI_Finalize(); return 1; } int* global_array = NULL; int local_size = 4; int* local_array = (int*)malloc(local_size * sizeof(int)); if (rank == 0) { // 主进程初始化全局数组 global_array = (int*)malloc(10 * sizeof(int)); for (int i = 0; i < 10; i++) global_array[i] = i*2; // 主进程直接拷贝自己需要的片段(比发送更高效) for (int i=0; i<4; i++) local_array[i] = global_array[i]; // 发送给进程1 MPI_Send(&global_array[3], 4, MPI_INT, 1, 0, MPI_COMM_WORLD); // 发送给进程2 MPI_Send(&global_array[6], 4, MPI_INT, 2, 0, MPI_COMM_WORLD); } else if (rank == 1) { MPI_Recv(local_array, 4, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if (rank == 2) { MPI_Recv(local_array, 4, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } // 验证输出 printf("Rank %d: Local array: ", rank); for (int i=0; i<local_size; i++) printf("%d ", local_array[i]); printf("\n"); if (rank ==0) free(global_array); free(local_array); MPI_Finalize(); return 0; }
额外提示
对于完整的CSR矩阵并行处理,后续还需要同步列索引数组和值数组的拆分,逻辑和行数组类似——需要根据行指针计算每个进程负责的非零元素数量,再用类似的MPI分发方法处理。
内容的提问来源于stack exchange,提问作者HARUN SASMAZ
相关产品推荐
相关产品推荐

