在我通常的 MPI-IO 倡导者角色中,请考虑 MPI-IO 来解决此类问题。您可以通过让每个进程写入文件来完全跳过收集。此外,如果 N 很大,您不希望进行 N 个文件操作。让 MPI(直接或通过库)让您的生活更轻松。
首先,基于文本的输出格式真的是您(和您的合作者)想要的吗?如果 Universe.out 变得足够大以至于您想要并行读取它,那么您将面临跨处理器分解文件的挑战。考虑并行 HDF5 (phdf5) 或 parallel-netcdf (pnetcdf) 或任何其他具有自描述可移植文件格式的高级库。
这是一个示例,说明如何写出所有 x 值,然后写出所有 y 值。
#include <stdio.h>
#include <mpi.h>
#include <unistd.h> //getpid
#include <stdlib.h> //srandom, random
#define MAX_PARTS 10
int main(int argc, char **argv) {
int rank, nprocs;
MPI_Offset nparts; // more than 2 billion particle possible
int i;
double *x, *y;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Offset start=0, x_end;
MPI_Info info;
MPI_File fh;
MPI_Status status;
srandom(getpid());
/* demonstrate this works even when particles are not evenly
* distributed over the processes */
nparts=((double)random()/RAND_MAX)*MAX_PARTS;
x = malloc(nparts*sizeof(*x));
y = malloc(nparts*sizeof(*y));
for (i = 0; i< nparts; i++) {
/* just some bogus data to see what happens */
x[i] = rank*100+i;
y[i] = rank*200+i;
}
/* not using this now. might tune later if needed */
MPI_Info_create(&info);
MPI_File_open(MPI_COMM_WORLD, "universe.out",
MPI_MODE_CREATE|MPI_MODE_WRONLY, info, &fh);
MPI_File_set_view(fh, 0, MPI_DOUBLE, MPI_DOUBLE, "native", info);
MPI_Scan(&nparts, &start, 1, MPI_OFFSET, MPI_SUM, MPI_COMM_WORLD);
/* MPI_Scan is a prefix reduction: remove our contribution */
x_end = start; /* only the last rank will use this in the bcast below */
start -= nparts;
MPI_Bcast(&x_end, 1, MPI_OFFSET, nprocs-1, MPI_COMM_WORLD);
MPI_File_write_at_all(fh, start, x, nparts, MPI_DOUBLE, &status);
MPI_File_write_at_all(fh, start+x_end, y, nparts, MPI_DOUBLE, &status);
MPI_Info_free(&info);
MPI_File_close(&fh);
MPI_Finalize();
}
可以将 x 数组和 y 数组写成 (x,y) 值对,但是
稍微复杂一点(你必须创建一个 MPI 数据类型)。
Parallel-NetCDF 有一个“操作组合”优化,可以为
你。 Parallel-HDF5 正在进行“多数据集 i/o”优化
下一个版本。通过这些优化,您可以定义一个 3d 数组,使用
x 和 y 为一维,“粒子标识符”为第三维。然后你
可以发布 x 值的操作,y 值的操作,以及
让图书馆将所有这些整合到一个电话中。