Использование нескольких ядер для обработки больших последовательных файлов в С++

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

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

Является ли это хорошим решением и существует ли простой способ его достижения?

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

обновить:

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

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


person Piotr    schedule 20.05.2011    source источник
comment
Какую обработку делаете?   -  person Björn Pollex    schedule 20.05.2011
comment
Я вижу в этом проблему: каждый набор операций чтения из (0, n/4, 2*n/4, 3*n/4) + i будет включать как минимум четыре обращения к диску, а ввод-вывод может стать узким местом.   -  person Piskvor left the building    schedule 20.05.2011
comment
@sehe: Вы правы, я слишком много предполагал.   -  person Piskvor left the building    schedule 20.05.2011
comment
@sehe: учитывая, что файл больше ОЗУ, я думаю, мы можем с уверенностью предположить, что он не на RAM-диске.   -  person MSalters    schedule 20.05.2011
comment
Вопрос @Space очень актуален, знаете ли вы, убивает ли вас IO или ваша обработка? Вы можете взглянуть на реализацию с отображением памяти (т. е. сопоставить блок, обработать, затем перейти к следующему блоку и т. д.). Это может помочь вам сократить количество операций ввода-вывода...   -  person Nim    schedule 20.05.2011
comment
Я делал тесты. IO не является узким местом, ЦП. И у меня много оперативной памяти для буферов. Мне нужно проанализировать запись (размер var, около 2000 байт каждая, записи разделены уникальным '\0' ), проверить ее, выполнить некоторые вычисления и записать результат в другой файл (ы).   -  person Piotr    schedule 20.05.2011


Ответы (5)


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

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

person SoapBox    schedule 20.05.2011

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

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

person Alexey Kukanov    schedule 20.05.2011

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

person MSalters    schedule 20.05.2011

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

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

person ianmac45    schedule 20.05.2011
comment
Да, жесткий диск не может читать из нескольких мест одновременно, но ОС буферизует ввод-вывод, поэтому один жесткий диск будет читать десятки записей. - person Piotr; 20.05.2011

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

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

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

person NPE    schedule 20.05.2011