C / C ++ Системный переносной способ изменения максимального количества открытых файлов - PullRequest
3 голосов
/ 19 мая 2011

У меня есть программа на 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();

Большое спасибо заранее!

Адам

Ответы [ 5 ]

2 голосов
/ 19 мая 2011

Существует как минимум два ограничения:

  • операционная система может наложить ограничение;в Unix (sh, bash и аналогичных оболочках) используйте ulimit для изменения предела, в пределах, разрешенных сисадмином
  • , реализация библиотеки C также может иметь ограничение;вам, вероятно, придется перекомпилировать библиотеку, чтобы изменить это значение

. Лучшее решение состоит в том, чтобы не иметь так много открытых файлов.В одной из моих собственных программ я написал оболочку для абстракции файла (это было в Python, но принцип тот же в C), который отслеживает текущую позицию файла в каждом файле и открывает / закрывает файлы по мере необходимости, сохраняя пул открытых в данный момент файлов.

1 голос
/ 19 мая 2011

Вы можете нормализовать входной файл во временный файл, чтобы каждая запись занимала одинаковое количество символов.Вы можете даже подумать о сохранении этого временного файла как двоичного (используя 4/8 байтов на число вместо 1 байта на десятичную цифру).Таким образом, вы можете рассчитать положение каждой записи в файле по его координатам в матрице.Затем вы можете получить доступ к определенным записям, выполнив std :: istream :: seekg , и вам не нужно ограничиваться количеством открытых файлов.

1 голос
/ 19 мая 2011

Нет переносимого способа изменить максимальное количество открытых файлов.Подобные ограничения, как правило, устанавливаются операционной системой и поэтому зависят от конкретной ОС.

Лучше всего сократить количество файлов, которые вы открываете одновременно.

0 голосов
/ 20 мая 2011

"Матрица слишком велика для хранения в памяти".Вполне вероятно, что матрица впишется в ваше адресное пространство.(Если матрица не помещается в 2 ^ 64 байта, вам понадобится очень впечатляющая файловая система для хранения всех этих временных файлов.) Так что не беспокойтесь о временных файлах.Пусть ОС управляет работой свопа на диске.Вам просто нужно убедиться, что вы обращаетесь к памяти таким образом, чтобы это было удобно для свопинга.На практике это означает, что у вас должна быть определенная местность.Но с 16 ГБ ОЗУ можно отобразить ~ 4 миллиона страниц ОЗУ. Если ваше количество столбцов значительно меньше, проблем не должно быть.

(Не используйте 32-битные системыдля этого, это просто не стоит боли)

0 голосов
/ 19 мая 2011

Как насчет создания 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] ;
...