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

如何逐行读取特定格式文件存入向量并实现MPI分发代码

问题描述

需要编写C程序读取特定格式的整数文件:首行是整数总数,后续每行一个随机整数,示例如下:

4
2
7
8
17

或

3
9
23
14

要求逐行读取文件并将整数存入向量,之后拆分向量分发到多个MPI进程执行后续任务。

尝试先统计文件行数再创建数组存储元素,但未成功,附上尝试代码:

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

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

     int rank, world_size;
     
     int root;
     int i;

     MPI_Init( &argc, &argv );
     MPI_Comm_rank( MPI_COMM_WORLD, &rank);

    if (rank == 0) { 
        
       char Line[100];
       char c;
       int count_lines=0;
       FILE *fp = fopen("Input_16.txt","r");
       for (c = getc(fp); c != EOF; c = getc(fp))
        if (c == '\n') // Increment count if this character is newline
           count_lines = count_lines + 1;
       
       int array[count_lines];
       for (i=0; i<count_lines; i++)
           array[i]=fgets(Line,100,fp);
           printf("Prints: %c \n",array[i]); 
           

}


    MPI_Finalize();
}

问题分析与修正

原代码核心问题

  • 文件指针位置错误:统计行数时已将指针读到EOF,后续fgets无法读取内容,需重置指针到文件开头。
  • 类型不匹配:fgets返回字符串指针,直接赋值给int数组完全错误,需用atoi或sscanf转成整数。
  • 逻辑错误:首行是整数个数,统计的行数比实际整数多1,应直接读取首行数值作为数组大小,而非统计行数。
  • 代码块缩进错误:第二个for循环的printf未包含在循环体内,仅执行一次。
  • 缺失错误检查:未判断fopen是否成功,文件不存在时会直接崩溃。

修正后的完整代码

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

int main(int argc, char *argv[]) {
    int rank, world_size;
    int i, total_numbers;
    int *data = NULL;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);

    if (rank == 0) {
        FILE *fp = fopen("Input_16.txt", "r");
        if (!fp) {
            perror("Failed to open file");
            MPI_Abort(MPI_COMM_WORLD, 1);
        }

        // 读取首行的整数总数
        if (fscanf(fp, "%d", &total_numbers) != 1) {
            fprintf(stderr, "Failed to read total number count\n");
            fclose(fp);
            MPI_Abort(MPI_COMM_WORLD, 1);
        }

        // 动态分配内存(避免变长数组兼容性问题)
        data = malloc(total_numbers * sizeof(int));
        if (!data) {
            perror("Failed to allocate memory");
            fclose(fp);
            MPI_Abort(MPI_COMM_WORLD, 1);
        }

        // 读取后续所有整数
        for (i = 0; i < total_numbers; i++) {
            if (fscanf(fp, "%d", &data[i]) != 1) {
                fprintf(stderr, "Failed to read number at index %d\n", i);
                free(data);
                fclose(fp);
                MPI_Abort(MPI_COMM_WORLD, 1);
            }
        }
        fclose(fp);

        // 验证读取结果
        printf("Rank 0 read %d numbers: ", total_numbers);
        for (i = 0; i < total_numbers; i++) {
            printf("%d ", data[i]);
        }
        printf("\n");
    }

    // -------------------------- MPI分发部分 --------------------------
    // 广播总个数给所有进程
    MPI_Bcast(&total_numbers, 1, MPI_INT, 0, MPI_COMM_WORLD);

    // 计算每个进程分配的数量(处理不均分情况)
    int local_count = total_numbers / world_size;
    int remainder = total_numbers % world_size;
    if (rank < remainder) {
        local_count++;
    }

    // 每个进程分配本地内存
    int *local_data = malloc(local_count * sizeof(int));
    if (!local_data) {
        perror("Failed to allocate local memory");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    // 使用MPI_Scatterv分发数据(支持不均分场景)
    int *sendcounts = NULL;
    int *displs = NULL;
    if (rank == 0) {
        sendcounts = malloc(world_size * sizeof(int));
        displs = malloc(world_size * sizeof(int));
        int offset = 0;
        for (i = 0; i < world_size; i++) {
            sendcounts[i] = (i < remainder) ? local_count : (local_count - 1);
            displs[i] = offset;
            offset += sendcounts[i];
        }
    }

    MPI_Scatterv(data, sendcounts, displs, MPI_INT,
                 local_data, local_count, MPI_INT,
                 0, MPI_COMM_WORLD);

    // 验证本地数据
    printf("Rank %d received %d numbers: ", rank, local_count);
    for (i = 0; i < local_count; i++) {
        printf("%d ", local_data[i]);
    }
    printf("\n");

    // 释放内存
    if (rank == 0) {
        free(data);
        free(sendcounts);
        free(displs);
    }
    free(local_data);

    MPI_Finalize();
    return 0;
}

关键说明

  1. 文件读取优化:直接读取首行的整数总数,省去统计行数的冗余操作;用fscanf直接读取整数,避免字符串转换步骤,更高效可靠。
  2. 内存安全:用malloc动态分配内存替代变长数组,提升兼容性;增加文件打开、内存分配的错误检查,避免程序崩溃。
  3. MPI分发逻辑:
    • 用MPI_Bcast广播总个数,让所有进程知晓需分配的内存大小。
    • 处理不均分场景:余数部分的进程多分配一个元素。
    • 用MPI_Scatterv替代MPI_Scatter,支持不同进程接收不同数量的数据。
  4. 错误处理:任何步骤失败时调用MPI_Abort终止所有进程,避免部分进程挂起。

内容的提问来源于stack exchange,提问作者Davey_flan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:55:28