Использование нескольких ядер для обработки большого последовательного файла в c ++ - PullRequest
10 голосов
/ 20 мая 2011

У меня большой файл (больше, чем ОЗУ, я не могу читать целиком за один раз), и мне нужно обрабатывать его строка за строкой (в c ++).Я хочу использовать несколько ядер, желательно с Intel TBB или Microsoft PPL .Я бы предпочел избежать предварительной обработки этого файла (например, разбить его на 4 части и т. Д.).

Я думал о чем-то вроде использования 4 итераторов, инициализированных (0, n / 4, 2 * n / 4 3 * n / 4) позиций в файле и т. Д.

Это так?хорошее решение и есть ли простой способ достижения этого?

Или, может быть, вы знаете некоторые библиотеки, которые поддерживают эффективное одновременное чтение потоков?

обновление :

Я делал тесты.IO не является узким местом, процессор есть.И у меня много оперативной памяти для буферов.

Мне нужно проанализировать запись (размер переменной, около 2000 байт каждая, записи разделены уникальным символом '\ 0'), проверить его, выполнить некоторые вычисления и записать результат в другой файл (ы)

Ответы [ 5 ]

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

Поскольку вы можете разбить его на N частей, похоже, что обработка каждой строки в значительной степени независима.В этом случае, я думаю, самое простое решение - настроить один поток для построчного чтения файла и поместить каждую строку в tbb::concurrent_queue.Затем создайте столько потоков, сколько вам нужно, чтобы извлечь строки из этой очереди и обработать их.

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

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

Я рекомендую использовать схему конвейера TBB. Первый последовательный этап конвейера считывает желаемую часть данных из файла; последующие этапы обрабатывают куски данных параллельно, а последний этап записывает в другой файл, возможно, в том же порядке, в котором данные были прочитаны.

Пример этого подхода доступен в дистрибутивах TBB; см. примеры / трубопровод / квадрат. Он использует «старый» интерфейс, класс tbb::pipeline и фильтры (классы, унаследованные от tbb::filter), которые передают данные с помощью void* указателей. Более новый, безопасный для типов и удобный для лямбды «декларативный» интерфейс tbb::parallel_pipeline() может быть более удобным в использовании.

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

ianmac уже намекнул на проблему поиска. Идея вашего итератора разумна с небольшим изменением: инициализируйте их равными 0,1,2 и 3, и увеличивайте каждый на 4. Итак, первый поток работает с элементами 0,4,8 и т. Д. ОС проверит файл подается в ваше приложение как можно быстрее. Возможно, ваша операционная система скажет, что вы будете выполнять последовательное сканирование файла (например, в Windows это флаг CreateFile).

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

Вы не очень много говорите о том, какой тип обработки вы собираетесь делать. Неясно, ожидаете ли вы, что процесс будет связан с вычислениями или вводом-выводом, существуют ли зависимости данных между обработкой разных строк и т. Д.

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

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

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

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

Однако обработка данных - это совсем другое дело, и вы можете легко сделать это в нескольких потоках.(Хранение данных в правильном порядке также не будет / не должно быть сложным).

...