因此,将大量数据写入文本并不是一个好主意。它真的非常非常慢,它会生成不必要的大文件,而且处理起来很痛苦。大量数据应以二进制形式编写,只有人类的摘要数据应以文本形式编写。使计算机要处理的内容对计算机来说变得容易,并且只有您实际上要坐下来阅读的内容对您来说才容易处理(例如,文本)。
无论您要写入文本还是二进制,都可以使用 MPI-IO 将输出协调到文件以生成一个大文件。我们有一个关于该主题的小教程(使用 MPI-IO、HDF5 和 NetCDF)here https://support.scinet.utoronto.ca/wiki/images/a/aa/ParIO-HPCS2011.pdf。对于 MPI-IO,诀窍是定义一个类型(此处为子数组)来根据文件的全局布局来描述数据的本地布局,然后使用它作为“视图”写入文件。每个文件仅看到自己的视图,并且 MPI-IO 库协调输出,以便只要视图不重叠,所有内容都会作为一个大文件出现。
如果我们以二进制形式写出来,我们只需将 MPI_Write 指向我们的数据即可完成;由于我们使用的是文本,因此必须将数据转换为字符串。我们按照通常的方式定义数组,只不过它不是 MPI_FLOAT,而是一种新类型,即charspernum
每个数字的字符数。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mpi.h>
float **alloc2d(int n, int m) {
float *data = malloc(n*m*sizeof(float));
float **array = malloc(n*sizeof(float *));
for (int i=0; i<n; i++)
array[i] = &(data[i*m]);
return array;
}
int main(int argc, char **argv) {
int ierr, rank, size;
MPI_Offset offset;
MPI_File file;
MPI_Status status;
MPI_Datatype num_as_string;
MPI_Datatype localarray;
const int nrows=10;
const int ncols=10;
float **data;
char *const fmt="%8.3f ";
char *const endfmt="%8.3f\n";
int startrow, endrow, locnrows;
const int charspernum=9;
ierr = MPI_Init(&argc, &argv);
ierr|= MPI_Comm_size(MPI_COMM_WORLD, &size);
ierr|= MPI_Comm_rank(MPI_COMM_WORLD, &rank);
locnrows = nrows/size;
startrow = rank * locnrows;
endrow = startrow + locnrows - 1;
if (rank == size-1) {
endrow = nrows - 1;
locnrows = endrow - startrow + 1;
}
/* allocate local data */
data = alloc2d(locnrows, ncols);
/* fill local data */
for (int i=0; i<locnrows; i++)
for (int j=0; j<ncols; j++)
data[i][j] = rank;
/* each number is represented by charspernum chars */
MPI_Type_contiguous(charspernum, MPI_CHAR, &num_as_string);
MPI_Type_commit(&num_as_string);
/* convert our data into txt */
char *data_as_txt = malloc(locnrows*ncols*charspernum*sizeof(char));
int count = 0;
for (int i=0; i<locnrows; i++) {
for (int j=0; j<ncols-1; j++) {
sprintf(&data_as_txt[count*charspernum], fmt, data[i][j]);
count++;
}
sprintf(&data_as_txt[count*charspernum], endfmt, data[i][ncols-1]);
count++;
}
printf("%d: %s\n", rank, data_as_txt);
/* create a type describing our piece of the array */
int globalsizes[2] = {nrows, ncols};
int localsizes [2] = {locnrows, ncols};
int starts[2] = {startrow, 0};
int order = MPI_ORDER_C;
MPI_Type_create_subarray(2, globalsizes, localsizes, starts, order, num_as_string, &localarray);
MPI_Type_commit(&localarray);
/* open the file, and set the view */
MPI_File_open(MPI_COMM_WORLD, "all-data.txt",
MPI_MODE_CREATE|MPI_MODE_WRONLY,
MPI_INFO_NULL, &file);
MPI_File_set_view(file, 0, MPI_CHAR, localarray,
"native", MPI_INFO_NULL);
MPI_File_write_all(file, data_as_txt, locnrows*ncols, num_as_string, &status);
MPI_File_close(&file);
MPI_Type_free(&localarray);
MPI_Type_free(&num_as_string);
free(data[0]);
free(data);
MPI_Finalize();
return 0;
}
运行给出:
$ mpicc -o matrixastxt matrixastxt.c -std=c99
$ mpirun -np 4 ./matrixastxt
$ more all-data.txt
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
2.000 2.000 2.000 2.000 2.000 2.000 2.000 2.000 2.000 2.000
2.000 2.000 2.000 2.000 2.000 2.000 2.000 2.000 2.000 2.000
3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000
3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000
3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000
3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000 3.000