首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MPI-2 並行IO完整指南:三種訪問模式/阻塞非阻塞/二進制文件實戰

     編輯:關於C語言

MPI-2 並行IO完整指南:三種訪問模式/阻塞非阻塞/二進制文件實戰

MPI-1 僅支持串行IO(0號進程讀寫再廣播),數據通信量大、擴展性差。MPI-2 引入並行IO,允許所有進程直接並發訪問文件,消除數據再分發開銷。本文系統講解三大訪問模式(顯式偏移/獨立文件指針/共享文件指針)、阻塞與非阻塞 API、二進制數組文件讀寫完整案例、文本↔二進制轉換工具,適合高性能計算開發者快速上手。

並行IO三大訪問模式對比

模式核心API指針管理適用場景同步特性
顯式偏移MPI_File_read_at_all MPI_File_write_at_all每次調用顯式指定偏移量固定佈局、隨機訪問、校驗點寫入集體操作,隱式屏障同步
獨立文件指針MPI_File_set_view + MPI_File_read_all MPI_File_write_all每進程維護私有文件指針流式讀寫、日誌、順序數據集體操作,指針獨立推進
共享文件指針MPI_File_seek_shared + MPI_File_read_ordered MPI_File_write_ordered所有進程共享單一指針順序寫入單一文件、協調輸出集體操作,按秩有序訪問

核心數據佈局:二維數組塊分佈

#define BLOCK_LOW(rank, size, n)   ((rank)*(n)/(size))
#define BLOCK_HIGH(rank, size, n)  (BLOCK_LOW((rank)+1,size,n)-1)
#define BLOCK_SIZE(rank, size, n)  (BLOCK_HIGH(rank,size,n)-BLOCK_LOW(rank,size,n)+1)

// 進程 rank 負責第 [BLOCK_LOW, BLOCK_HIGH] 行,共 BLOCK_SIZE 行

完整案例:二進制矩陣文件並行讀寫

文件格式

[行數:int][列數:int][數據:float[row][col] 行主序]

模式一:顯式偏移(推薦,最靈活高效)

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

    MPI_File fh; MPI_Status st;
    int n, m; float* local_data;

    // 1. 打開文件
    MPI_File_open(MPI_COMM_WORLD, "data", MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);

    // 2. 所有進程讀取行列數(偏移0和sizeof(int))
    MPI_File_read_at_all(fh, 0, &n, 1, MPI_INT, &st);
    MPI_File_read_at_all(fh, sizeof(int), &m, 1, MPI_INT, &st);

    // 3. 分配局部緩衝並讀取數據
    int local_rows = BLOCK_SIZE(rank, size, n);
    local_data = malloc(local_rows * m * sizeof(float));
    MPI_Offset offset = 2*sizeof(int) + BLOCK_LOW(rank,size,n)*m*sizeof(float);
    MPI_File_read_at_all(fh, offset, local_data, local_rows*m, MPI_FLOAT, &st);

    MPI_File_close(&fh);

    // 4. 驗證輸出(進程0)
    if (rank == 0) { /* 打印局部數據 */ }

    // 5. 寫入新文件(同理用 MPI_File_write_at_all)
    MPI_File_open(MPI_COMM_WORLD, "data2", MPI_MODE_CREATE|MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
    MPI_File_write_at_all(fh, 0, &n, 1, MPI_INT, &st);
    MPI_File_write_at_all(fh, sizeof(int), &m, 1, MPI_INT, &st);
    MPI_File_write_at_all(fh, offset, local_data, local_rows*m, MPI_FLOAT, &st);
    MPI_File_close(&fh);

    MPI_Finalize(); return 0;
}

模式二:獨立文件指針

// 關鍵差異:用 set_view 設置起始視圖,read_all/write_all 自動推進指針
MPI_File_set_view(fh, 0, MPI_INT, MPI_INT, "native", MPI_INFO_NULL);
MPI_File_read_all(fh, &n, 1, MPI_INT, &st);
MPI_File_read_all(fh, &m, 1, MPI_INT, &st);

// 重置視圖到數據區
MPI_Offset data_offset = 2*sizeof(int) + BLOCK_LOW(rank,size,n)*m*sizeof(float);
MPI_File_set_view(fh, data_offset, MPI_FLOAT, MPI_FLOAT, "native", MPI_INFO_NULL);
MPI_File_read_all(fh, local_data, local_rows*m, MPI_FLOAT, &st);

模式三:共享文件指針

// 關鍵差異:共享指針 + ordered 操作(按 rank 順序訪問)
MPI_File_read_at_all(fh, 0, &n, 1, MPI_INT, &st);  // 讀頭部仍用顯式偏移
MPI_File_read_at_all(fh, sizeof(int), &m, 1, MPI_INT, &st);

MPI_File_seek_shared(fh, 2*sizeof(int), MPI_SEEK_SET);  // 共享指針定位
MPI_File_read_ordered(fh, local_data, local_rows*m, MPI_FLOAT, &st);  // 按秩順序讀

// 寫入同理
MPI_File_write_at_all(fh, 0, &n, 1, MPI_INT, &st);
MPI_File_write_at_all(fh, sizeof(int), &m, 1, MPI_INT, &st);
MPI_File_seek_shared(fh, 2*sizeof(int), MPI_SEEK_SET);
MPI_File_write_ordered(fh, local_data, local_rows*m, MPI_FLOAT, &st);

非阻塞並行IO(異步)

MPI_Request req;
MPI_File_iread_at(fh, offset, buf, count, datatype, &req);  // 發起異步讀
// ... 進行計算 ...
MPI_Wait(&req, &st);  // 等待完成
// 同理:MPI_File_iwrite_at, MPI_File_iread_all, MPI_File_iwrite_all

二進制↔文本轉換工具(驗證數據正確性)

二進制 → 文本

FILE* fp = fopen("data", "rb");
fread(&n, sizeof(int), 1, fp);
fread(&m, sizeof(int), 1, fp);
float** a = malloc(n*sizeof(float*));
a[0] = malloc(n*m*sizeof(float));
for (int i=1; i

文本 → 二進制

FILE* fp = fopen("data.txt", "r");
fscanf(fp, "%d%d", &n, &m);
// 分配同上
for (int i=0; i

樣例文本文件 data.txt

8 8
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
2.0 2.0 2.0 2.0 2.0 2.0 2.0 2.0
3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0
4.0 4.0 4.0 4.0 4.0 4.0 4.0 4.0
5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0
6.0 6.0 6.0 6.0 6.0 6.0 6.0 6.0
7.0 7.0 7.0 7.0 7.0 7.0 7.0 7.0
8.0 8.0 8.0 8.0 8.0 8.0 8.0 8.0

最佳實踐總結

  1. 優先選擇顯式偏移:語義清晰、無隱式狀態、易於調試、性能最優
  2. 集體操作(_all)必須全進程參與:否則死鎖
  3. 文件視圖設置一次:避免重複 set_view 開銷
  4. 非連續內存用派生數據類型:MPI_Type_vector / MPI_Type_hvector 描述子數組佈局
  5. 錯誤檢查:每個 MPI_File_* 調用檢查返回碼,MPI_Error_string 獲取信息
  6. 原子性寫入:關鍵數據用 MPI_File_sync 強制刷盤

總結

MPI-2 並行IO 通過 顯式偏移、獨立指針、共享指針 三種模式覆蓋所有訪問模式。二維數組塊分佈配合 MPI_File_read_at_all/write_at_all 是最高效、最常用的模式。掌握本文案例代碼、數據佈局宏、二進制驗證工具,即可在 HPC 應用中實現高性能、可擴展的並行文件讀寫,徹底擺脫 MPI-1 串行IO 瓶頸。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved