You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

代码关键解释

  1. 进程合法性检查:先确保运行时进程数为3,避免不符合需求的执行。
  2. 数组分配:主进程负责初始化全局行数组,所有进程根据需求分配本地数组内存。
  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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 18:07:36