Эффективный способ сохранения данных на диск при выполнении ресурсоемкой задачи.

Я работаю над частью научного программного обеспечения, которое очень интенсивно использует процессор (его привязка к процессу), но ему необходимо довольно часто записывать данные на диск (привязка ввода-вывода).

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

Я ищу «лучшую практику» для этого, и меня больше всего волнует скорость (это могут быть очень длинные симуляции).

Спасибо ~ Алекс

Первые мысли:

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

Возможно труба/буфер? Я новичок в этом, так что, возможно, это может быть возможным решением.


person machinaut    schedule 18.06.2009    source источник


Ответы (6)


Если вы внедряете OpenMP в свою программу, то лучше использовать #pragma omp single или #pragma omp master из параллельного раздела для сохранения в файл. Эти прагмы позволяют выполнять что-либо только одному потоку. Итак, ваш код может выглядеть следующим образом:

#pragma omp parallel
{
    // Calculating the first part
    Calculate();

    // Using barrier to wait all threads
    #pragma omp barrier

    #pragma omp master
    SaveFirstPartOfResults();

    // Calculate the second part
    Calculate2();

    #pragma omp barrier

    #pragma omp master
    SaveSecondPart();

    Calculate3();

    // ... and so on
}

Здесь команда потоков будет выполнять вычисления, но только один поток будет сохранять результаты на диск.

Похоже на программный конвейер. Я предлагаю вам рассмотреть шаблон tbb::pipeline из библиотеки Intel Threading Building Blocks. Я могу отослать вас к руководству по программным конвейерам по адресу http://cache-www.intel.com/cd/00/00/30/11/301132_301132.pdf#page=25. Пожалуйста, прочитайте пункт 4.2. Они решили проблему: один поток для чтения с диска, второй для обработки прочитанных строк, третий для сохранения на диск.

person Vladimir Obrizan    schedule 20.06.2009

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

person Paul Sonier    schedule 18.06.2009

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

Проблема в том, что на самом деле ваш цикл моделирования не завершен, пока он не выдаст результаты.

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

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

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

person Michael Kohne    schedule 18.06.2009
comment
Я думаю, что тогда я выберу одностороннюю трубу. Я не думаю, что слишком сильно столкнусь с проблемой блокировки; генерируемых данных не так много, я просто хотел разделить потоки. Если бы я генерировал столько данных, я бы пересмотрел, сколько на самом деле нужно хранить. - person machinaut; 18.06.2009

Поскольку вы привязаны к процессору и вводу-выводу: дайте угадаю: памяти еще много, верно?

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

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

Также вы всегда можете немного поторговаться между процессором и вводом-выводом. Я думаю, вы в настоящее время записываете данные как какие-то необработанные, несжатые данные, верно? Вы можете получить некоторую производительность ввода-вывода, если используете простую схему сжатия для уменьшения объема записываемых данных. С библиотекой ZLIB довольно легко работать, и она очень быстро сжимается на самом низком уровне сжатия. Это зависит от характера ваших данных, но если в них много избыточности, даже очень грубый алгоритм сжатия может устранить проблему ограничения ввода-вывода.

person Nils Pipenbrinck    schedule 18.06.2009

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

person yfeldblum    schedule 18.06.2009

Создайте в приложении два потока, один для ЦП и один для жесткого диска.

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

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

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

person samoz    schedule 18.06.2009