Обрабатывать один и тот же файл в двух потоках, используя ifstream - PullRequest
5 голосов
/ 02 июня 2011

У меня есть входной файл в моем приложении, который содержит огромное количество информации. Чтение по нему последовательно, и только по одному смещению файла за раз недостаточно для использования моего приложения. В идеале я хотел бы иметь два потока, которые имеют отдельные и отличные чтения ifstream из двух уникальных смещений файла одного и того же файла. Я не могу просто запустить один ifstream, а затем скопировать его, используя его конструктор копирования (так как он не копируемый). Итак, как мне справиться с этим?

Сразу могу придумать два пути,

  1. Создайте новый ifstream для второго потока, откройте его в том же файле.
  2. Совместное использование одного экземпляра открытого ifstream в обоих потоках (например, boost::shared_ptr<>). Ищите соответствующее смещение файла, в котором текущий поток заинтересован, когда поток получает временной интервал.

Является ли предпочтительным один из этих двух методов?

Есть ли третий (или четвертый) вариант, о котором я еще не подумал?

Очевидно, что я в конечном счете ограничен тем, что жесткий диск должен вращаться взад-вперед, но я заинтересован в том, чтобы воспользоваться преимуществами (если возможно), некоторого кэширования диска на уровне ОС при обоих смещениях файлов одновременно.

Спасибо.

Ответы [ 5 ]

9 голосов
/ 02 июня 2011

Два std::ifstream экземпляра, вероятно, будут лучшим вариантом здесь. Современные жесткие диски оптимизированы для большой очереди запросов ввода-вывода, поэтому чтение из двух экземпляров std::ifstream одновременно должно давать довольно хорошую производительность.

Если у вас есть один std::ifstream, вам придется беспокоиться о синхронизации доступа к нему, плюс это может нарушить автоматическое кэширование с упреждающим чтением в операционной системе, что приведет к снижению производительности.

6 голосов
/ 02 июня 2011

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

Для третьего варианта передать ссылку или необработанный указатель в другой поток. Пока семантика такова, что один поток «владеет» istream, необработанный указатель или ссылка в порядке.

Наконец, обратите внимание, что на подавляющем большинстве аппаратных средств диск является узким местом, а не процессором при загрузке больших файлов. Использование двух потоков сделает это хуже , потому что вы превращаете последовательный доступ к файлу в произвольный доступ. Типичные жесткие диски могут работать со скоростью 100 МБ / с, но с максимальной скоростью 3 или 4 МБ / с.

4 голосов
/ 02 июня 2011

Другая опция:

  • Карта памяти файла, создайте столько объектов памяти, сколько вам нужно.(istrstream хорошо для этого, istringstream нет).
1 голос
/ 02 июня 2011

Это действительно зависит от вашей системы.Современная система обычно читает вперед;поиск в файле, вероятно, будет препятствовать этому, поэтому его следует избегать.

Возможно, стоит поэкспериментировать, как в вашей системе работает упреждающее чтение: откройте файл, затем последовательно прочитайте его первую половину и посмотрите, сколько времени это займет.Затем откройте его, найдите середину и последовательно прочитайте вторую половину.(В некоторых системах, которые я видел в прошлом, простой поиск в любой момент отключит опережающее чтение.) Наконец, откройте его, а затем прочитайте все остальные записи;это симулирует два потока, используя один и тот же дескриптор файла.(Для всех этих тестов используйте записи фиксированной длины и открывайте их в двоичном режиме. Также примите все необходимые меры, чтобы убедиться, что любые данные из файла удаляются из кэша ОС перед началом теста - в Unix, копируя файлДля этого обычно достаточно 10 или 20 Гигабайт до /dev/null.

Это даст вам некоторые идеи, но, чтобы быть уверенным, лучшим решением было бы проверить реальные случаи. Я был бы удивлен, еслиобщий доступ к одному ifstream (и, следовательно, одному дескриптору файла) и постоянный поиск выиграл, но вы никогда не знаете.

Я бы также порекомендовал системные решения, такие как mmap, но если выИмея столько данных, есть большая вероятность, что вы все равно не сможете отобразить все это за один раз (вы все равно можете использовать mmap, отображая их разделы за раз, но это становится намного сложнее).

Наконец, возможно ли будет вырезать данные, уже разрезанные на более мелкие файлы? Это может быть самым быстрым решением из всех. (В идеале это можно было бы сделать, еслиДанные создаются или импортируются в систему.)

0 голосов
/ 02 июня 2011

Моим голосом будет один читатель, который передает данные нескольким рабочим потокам.

Если ваш файл находится на одном диске, то несколько читателей снизят вашу производительность чтения. Да, у вашего ядра могут быть фантастические возможности кэширования или организации очередей, но оно будет тратить больше времени на поиск, чем на чтение данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...