Многопоточное чтение из файла на c++?

мое приложение использует текстовый файл для хранения данных в файл. Я тестировал самый быстрый способ чтения его с помощью многопоточности операции. Я использовал следующие 2 метода:

  1. используйте столько потоков, сколько переменная среды NUMBER_OF_PROCESSORS. Каждый поток находится в другом потоке. Разделите total no строк в файле поровну для каждого потока. Разберите текст.

  2. только один поток парсит весь файл и загружает данные в память. Создайте потоки (= NUMBER_OF_PROCESSORS-1) для анализа данных из памяти.

тест был запущен на различных размерах файлов 100kB-800MB. Данные в файле:

100.23123 -42343.342555 ...(and so on)
4928340 -93240.2 349 ...
...

данные хранятся в 2D массиве double.

результат: оба метода занимают примерно одно и то же время для анализа файла.

вопрос: какой метод я должен выбрать?

метод 1 плох для жесткого диска как многократное чтение доступ осуществляется в произвольных местах одновременно.

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

3 ответов


Метод 2 имеет последовательное узкое место (однопоточное считывание и раздача рабочих элементов). Это не будет масштабироваться бесконечно в соответствии с законом Amdahls. Однако это очень справедливый и надежный метод.

Способ 1 не узкое место и масштаб. Убедитесь, что на диске нет случайного ввода-вывода. Я бы использовал мьютекс, чтобы читать только один поток за раз. Читайте в большом последовательном блоке, возможно, 4-16MB. В то время как диск делает одну головку, он мог бы прочитать о 1MB данных.

Если разбор строк занимает значительное количество времени, вы не можете использовать метод 2 из-за большой последовательной части. Он не будет масштабироваться. Если синтаксический анализ выполняется быстро, используйте метод 2, потому что его легче получить правильно.

чтобы проиллюстрировать концепцию узкого места: представьте, что 1.000.000 вычислительных потоков просят один поток чтения дать им строки. Этот один поток читателей не сможет продолжать раздавать строки так быстро, как они требуются. Вы не были вам 1e6 раз пропускную способность. Это не будет масштабироваться. Но если потоки 1e6 считываются независимо от очень быстрого устройства ввода-вывода, вы получите пропускную способность в 1e6 раз, потому что нет узкого места. (Я использовал экстремальные числа,чтобы доказать это. То же самое относится и к малому.)


Я бы предпочел слегка модифицированный метод 2. Я бы читал данные последовательно в одном потоке большими кусками. Готовый фрагмент передается в пул потоков, где обрабатываются данные. Таким образом, у вас есть параллельное чтение и обработка


с достаточным количеством ОЗУ вы можете сделать это без узкого места с одной нитью. Для Linux:

1) mmap вы весь файл в ОЗУ с MAP_LOCKED, требует корневых или общесистемных разрешений настройки. Или без MAP_LOCKED для SSD, они хорошо справляются со случайным доступом.

2) Дайте каждому потоку начальную позицию. Обрабатывать данные из первой строки после установки запустить себя для первой строки после установки запустить поток.

PS какова загрузка процессора вашей программы? Вероятно, HDD-это горлышко бутылки.