Эффективный способ сохранения данных на диск при выполнении ресурсоемкой задачи.
-
06-07-2019 - |
Вопрос
Я работаю над научным программным обеспечением, которое очень интенсивно использует процессор (его привязка к процессору), но ему необходимо довольно часто записывать данные на диск (привязка ввода-вывода).
Я добавляю к этому распараллеливание (OpenMP) и мне интересно, как лучше всего удовлетворить потребности записи на диск.Нет причин, по которым симуляция должна ждать на жестком диске (что она и делает сейчас).
Я ищу «лучшую практику» для этого, и скорость — это то, что меня волнует больше всего (это могут быть очень длинные симуляции).
Спасибо ~ Алекс
Первые мысли:
наличие отдельного процесса выполняет фактическую запись на диск, поэтому симуляция состоит из двух процессов:один привязан к ЦП (моделирование), а другой — к вводу-выводу (запись файла).Это звучит сложно.
Возможно, труба/буфер?Я новичок в этом, так что, возможно, это может быть возможным решением.
Решение
Если вы реализуете OpenMP в своей программе, лучше использовать #pragma omp сингл или #прагма омп мастер из параллельного раздела для сохранения в файл.Эти прагмы позволяют только одному потоку выполнять что-либо.Итак, ваш код может выглядеть следующим образом:
#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.Они решили проблему:один поток для чтения с диска, второй для обработки прочитанных строк, третий для сохранения на диск.
Другие советы
Я бы сказал, что лучшим способом было бы создать другой поток для сохранения данных, а не совершенно новый процесс;с новым процессом вы сталкиваетесь с проблемой передачи сохраняемых данных через границу процесса, что создает новый набор трудностей.
Первое решение, которое приходит на ум, во многом соответствует тому, что вы сказали: запись на диск осуществляется в отдельном процессе с односторонним каналом от сима к записывающему устройству.Модуль записи записывает как можно быстрее (извлекая новые данные из канала).Проблема в том, что если сим слишком далеко опережает записывающего, сим в любом случае будет блокировать запись в канал, и он будет привязан к вводу-выводу за одно удаление.
Проблема в том, что на самом деле ваш цикл моделирования не завершен, пока не будут выданы результаты.
Второе, что мне приходит в голову, — это использовать неблокирующий ввод-вывод.Всякий раз, когда симу необходимо писать, он должен делать это через неблокирующий ввод-вывод.При следующей необходимости записи он может получить результаты предыдущей операции ввода-вывода (возможно, с небольшим ожиданием) перед началом новой.Это позволяет симуляции работать максимально параллельно с вводом/выводом, не позволяя симуляции сильно опережать запись.
Первое решение было бы лучше, если бы цикл обработки моделирования менялся (иногда меньше, чем время записи, иногда дольше), потому что в среднем записи могут идти в ногу с симуляцией.
Если цикл обработки всегда (или почти всегда) будет короче времени записи, то вы также можете не беспокоиться о трубе и просто использовать не блокирующий ввод-вывод, потому что, если вы используете трубу, она в конечном итоге заполнит И в любом случае сима будет задержаться на вводе/выводе.
Поскольку вы привязаны к процессору и вводу-выводу:Дайте угадаю:Памяти еще достаточно, верно?
В этом случае вам следует в определенной степени буферизовать данные, которые должны быть записаны на диск, в памяти.Запись огромных объемов данных обычно происходит намного быстрее, чем запись небольших фрагментов.
По самому написанию:Рассмотрите возможность использования ввода-вывода с отображением в памяти.Прошло много времени с тех пор, как я проводил тесты, но в прошлый раз это было значительно быстрее.
Также вы всегда можете торговать процессорами и процессорами.ИО немного.Я думаю, вы сейчас записываете данные в виде необработанных несжатых данных, верно?Вы можете получить некоторую производительность ввода-вывода, если используете простую схему сжатия для уменьшения объема записываемых данных.С библиотекой ZLIB довольно легко работать, и она очень быстро сжимает данные на самом низком уровне сжатия.Это зависит от характера ваших данных, но если в них много избыточности, даже очень грубый алгоритм сжатия может устранить проблему, связанную с вводом-выводом.
Один поток постоянно выполняет шаг трудоемкого процесса, а затем добавляет частичный результат в очередь частичных результатов.Другой поток постоянно удаляет частичные результаты из очереди и записывает их на диск.Обязательно синхронизируйте доступ к очереди.Очередь — это структура данных в виде списка, в которой вы можете добавлять элементы в конец и удалять элементы в начале.
Сделайте так, чтобы в вашем приложении было два потоки, один для процессора и один для жесткого диска.
Пусть поток ЦП помещает завершенные данные в очередь, из которой поток жесткого диска затем извлекает данные по мере их поступления.
Таким образом, ЦП просто избавляется от данных и позволяет кому-то другому их обработать, а жесткий диск просто терпеливо ждет любых данных в своей очереди.
С точки зрения реализации вы могли бы реализовать очередь как объект с общей памятью, но я думаю, что канал — это именно то, что вам нужно.Процессор просто записывает в канал, когда это необходимо.Что касается жесткого диска, вы просто прочитаете канал и, как только получите действительные данные, продолжите работу оттуда.