TLDR
当我并行生成文件时,For 循环挂起。为什么? (见下面的代码)此外,写入多个二进制文件(指针和偏移量由迭代变量确定)的安全/有效方法是什么?
背景和问题:
我希望我的代码执行以下操作:
(1) 所有进程都读取一个包含 double 矩阵的二进制文件 -> 已经使用 MPI_File_read_at() 实现了这一点
(2) 对于每个“列”的输入数据,使用每个“行”中的数字执行计算,并将每一列的数据保存到它自己的二进制输出文件中(“File0.bin” -> column 0)
(3) 为了使用户能够指定任意数量的进程,我使用简单的索引将矩阵视为一个长(行)X(列) vector ,并按进程数拆分该 vector 。每个进程获取 (rows)X(cols)/tot_proc 要处理的条目...使用这种方法,列不会被每个进程整齐地划分,因此,每个进程需要访问与其对应的任何文件,并且,使用适当的偏移量,写入正确文件的正确部分。目前,生成的文件是否碎片化并不重要。
在我朝着这个目标努力的过程中,我编写了一个简短的程序来循环创建二进制文件,但循环在最后一次迭代时挂起(13 个文件分为 4 个进程)。要创建的文件数 =(行)。
问题 1 为什么这段代码会在循环的最后挂起?在我的 4 个进程的玩具示例中,id_proc 1-3 有 3 个文件要创建,而 id_proc 0(根进程)有 4 个文件要创建。当根进程试图创建它的第 4 个文件时,循环挂起。注意:我正在使用 mpic++ 在运行 Ubuntu 的笔记本电脑上编译它。
问题 2 最后,我将添加第二个 for 循环,就像您在下面看到的那样,除了在这个循环中,进程必须写入已创建的二进制文件的适当部分.我计划使用 MPI_File_write_at() 来执行此操作,但我还读到文件应该使用 MPI_File_set_size() 静态调整大小,然后,每个进程都应该使用 MPI_File_set_view() 拥有自己的文件 View 。所以,我的问题是,为了让它发挥作用,我应该执行以下操作吗?
(循环 1)MPI_File_open(...,MPI_WRONLY | MPI_CREATE,...), MPI_File_set_size(), MPI_File_close()
(循环 2)MPI_File_open(...,MPI_WRONLY,...), MPI_File_set_view(), MPI_File_write_at(), MPI_File_close()
.... 循环 2 似乎会因为每次迭代都必须打开和关闭文件而变慢,但我事先不知道用户将提供多少输入数据,也不知道用户将提供多少进程。例如,进程 N 可能需要写入文件 1 的末尾、文件 2 的中间和文件 8 的末尾。原则上,所有这些都可以通过偏移来处理。我不知道 MPI 是否允许这种级别的灵 active 。
尝试并行创建多个文件的代码:
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <vector>
#include <fstream>
#include <string>
#include <sstream>
#include <cmath>
#include <sys/types.h>
#include <sys/stat.h>
#include <mpi.h>
using namespace std;
int main(int argc, char** argv)
{
//Variable declarations
string oname;
stringstream temp;
int rows = 13, cols = 7, sz_dbl = sizeof(double);
//each binary file will eventually have 7*sz_dbl bytes
int id_proc, tot_proc, loop_min, loop_max;
vector<double> output(rows*cols,1.0);//data to write
//MPI routines
MPI_Init(&argc,&argv);//initialize MPI
MPI_Comm_rank(MPI_COMM_WORLD,&id_proc);//get "this" node's id#/rank
MPI_Comm_size(MPI_COMM_WORLD,&tot_proc);//get the number of processors
//MPI loop variable assignments
loop_min = id_proc*rows/tot_proc + min(rows % tot_proc, id_proc);
loop_max = loop_min + rows/tot_proc + (rows % tot_proc > id_proc);
//File handle
MPI_File outfile;
//Create binary files in parallel
for(int i = loop_min; i < loop_max; i++)
{
temp << i;
oname = "Myout" + temp.str() + ".bin";
MPI_File_open(MPI_COMM_WORLD, oname.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &outfile);
temp.clear();
temp.str(string());
MPI_File_close(&outfile);
}
MPI_Barrier(MPI_COMM_WORLD);//with or without this, same error
MPI_Finalize();//MPI - end mpi run
return 0;
}
到目前为止我已阅读的教程/信息页面:
http://beige.ucs.indiana.edu/B673/node180.html
http://beige.ucs.indiana.edu/B673/node181.html
http://mpi-forum.org/docs/mpi-2.2/mpi22-report/node305.htm
https://www.open-mpi.org/doc/v1.4/man3/MPI_File_open.3.php
http://www.mcs.anl.gov/research/projects/mpi/mpi-standard/mpi-report-2.0/node215.htm
最佳答案
MPI_File_open()
是一个集体操作,这意味着来自MPI_COMM_WORLD
的所有任务必须在相同的时间打开相同 文件时间。
如果您想为每个任务打开一个进程,请改用 MPI_COMM_SELF
。
关于c++ - MPI二进制文件I/O基本功能和性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44711715/