2011-05-19 21 views
3

我有一个C++程序,转置一个非常大的矩阵。该矩阵太大而无法保存在内存中,因此我将每列写入一个单独的临时文件,然后在整个矩阵处理完成后连接临时文件。但是,现在我发现我遇到了打开太多临时文件的问题(即操作系统不允许我打开足够的临时文件)。是否有一个系统可移植的方法来检查(并希望更改)允许的最大数量的打开文件?C/C++系统可移动的方式来改变打开的文件的最大数量

我意识到我可以关闭每个临时文件并只在需要时重新打开,但是担心这样做会对性能造成影响。

我的代码工作如下(伪 - 不能保证工作):

int Ncol=5000; // For example - could be much bigger. 
int Nrow=50000; // For example - in reality much bigger. 

// Stage 1 - create temp files 
vector<ofstream *> tmp_files(Ncol); // Vector of temp file pointers. 
vector<string> tmp_filenames(Ncol); // Vector of temp file names. 
for (unsigned int ui=0; ui<Ncol; ui++) 
{ 
    string filename(tmpnam(NULL)); // Get temp filename. 
    ofstream *tmp_file = new ofstream(filename.c_str()); 
    if (!tmp_file->good()) 
     error("Could not open temp file.\n"); // Call error function 
    (*tmp_file) << "Column" << ui; 
    tmp_files[ui] = tmp_file; 
    tmp_filenames[ui] = filename; 
} 

// Stage 2 - read input file and write each column to temp file 
ifstream input_file(input_filename.c_str()); 
for (unsigned int s=0; s<Nrow; s++) 
{ 
     int input_num; 
     ofstream *tmp_file; 
     for (unsigned int ui=0; ui<Ncol; ui++) 
     { 
      input_file >> input_num; 
      tmp_file = tmp_files[ui];   // Get temp file pointer 
      (*tmp_file) << "\t" << input_num; // Write entry to temp file. 
     } 
} 
input_file.close(); 

// Stage 3 - concatenate temp files into output file and clean up. 
ofstream output_file("out.txt"); 
for (unsigned int ui=0; ui<Ncol; ui++) 
{ 
     string tmp_line; 
     // Close temp file 
     ofstream *tmp_file = tmp_files[ui]; 
     (*tmp_file) << endl; 
     tmp_file->close(); 

     // Read from temp file and write to output file. 
     ifstream read_file(tmp_filenames[ui].c_str()); 
     if (!read_file.good()) 
      error("Could not open tmp file for reading."); // Call error function 
     getline(read_file, tmp_line); 
     output_file << tmp_line << endl; 
     read_file.close(); 

     // Delete temp file. 
     remove(tmp_filenames[ui].c_str()); 
} 
output_file.close(); 

提前非常感谢!

亚当

+0

便携式系统在Windows <-> * nix的便携感?不要以为你可以在Windows上设置这个参数。 – RedX 2011-05-19 14:06:59

+0

如果您将这些数字存储为文本,那么您将会以所有从文本到数值的转换来惩罚您的表现。 – Andrew 2011-05-19 15:10:19

+0

我正在阅读的格式是一种标准化生物信息学格式,其中列可以实际包含各种数字,文本字符串等。不幸的是,从文本到数字的转换是不可避免的。 (有问题的格式在这里:http://www.1000genomes.org/wiki/Analysis/Variant%20Call%20Format/vcf-variant-call-format-version-41) – Adam 2011-05-19 15:15:16

回答

2

至少有两个限制:

  • 操作系统可施加限制;在Unix(sh,bash和类似的shell)中,使用ulimit更改限制,在由sysadmin允许的范围内,C库实现也可能有限制;你可能需要重新编译库来改变它

更好的解决方案是避免有这么多打开的文件。在我自己的程序之一中,我编写了一个文件抽象的封装(这是用Python编写的,但原理与C相同),它跟踪每个文件中当前文件的位置,并根据需要打开/关闭文件,保持当前打开的文件池。

1

没有一种可移动的方式来改变打开文件的最大数量。这样的限制往往是由操作系统强加的,因此是特定于操作系统的。

最好的办法是减少任何时候打开的文件数量。

0

如何制作1个大文件而不是许多小临时文件? Seek是一个便宜的操作。无论如何,你的专栏应该都是相同的大小。您应该能够将文件指针放在需要访问列的位置。

// something like... 

column_position = sizeof(double)*Nrows*column ; 
is.seekg(column_position) ; 
double column[Nrows] ; 
for(i = 0 ; i < Nrows ; i++) 
    is >> column[i] ; 
+0

你能扩展你的意思吗?在原始文件寻找找到列?或者在临时文件中查找?对不起 - 我没跟着。 – Adam 2011-05-19 14:20:17

+0

不幸的是,我正在阅读的文件是文本(一种标准化的生物信息学格式),因此无法以这种方式进行查找。 (还是)感谢你的建议。 – Adam 2011-05-19 15:14:14

+0

和你的临时文件?他们在什么格式? – Andrew 2011-05-19 15:35:24

1

您可以将输入文件标准化为临时文件,使每个条目占用相同数量的字符。您甚至可以考虑将该临时文件保存为二进制文件(每个数字使用4/8个字节,而不是每个十进制数字1个字节)。通过这种方式,您可以根据矩阵中的坐标计算文件中每个条目的位置。然后,您可以通过执行std::istream::seekg来访问特定条目,而且您不必关心打开文件的数量限制。

0

“矩阵太大而无法保存在内存中”。不过,这个矩阵很可能会适合你的地址空间。 (如果矩阵不适合2^64字节,则需要一个非常令人印象深刻的文件系统来保存所有这些临时文件。)因此,不要担心临时文件。让操作系统处理交换到磁盘的工作方式。您只需确保以友好的交换方式访问内存。实际上,这意味着你需要有一些参考地点。但是,使用16 GB的RAM,可以映射大约400万页的RAM。如果你的柱子数量明显小于这个数量,应该没有问题。

(不要使用这个32个系统,它只是不值得的痛苦)