Чтение многих файлов параллельно

У меня есть кроссплатформенный проект на C ++, где я микширую аудио в режиме реального времени. У меня есть несколько независимых треков для ввода, которые я читаю из отдельных файлов на диске. Затем я смешал их, применил некоторую обработку и выплюнул буфер с полученным звуком. У меня проблема со скоростью дискового ввода-вывода. Для текущего теста, который я выполняю, у меня есть около 10 треков, которые считываются одновременно с диска. Каждый трек в необработанном формате PCM, 48000 Гц, 16-битное стерео. Это означает, что существует значительный объем данных, которые необходимо прочитать как можно быстрее. Я пробовал как простые вызовы fread, так и файлы с отображением в памяти через Boost, но проблема та же. Когда файл открывается впервые, это обычно приводит к прерыванию звука (предположительно, когда файл считывается в кэш ОС). После этого все работает без сбоев. В настоящее время я использую один поток на файл в общем случае, иногда два файла на поток. Обычно, когда у меня есть два файла на поток, происходит остановка / разрыв потока. Обратите внимание, что я заранее не знаю, какие входные файлы нужно воспроизводить, так как это контролируется пользователем. Поэтому моя проблема заключается в том, как прочитать эти начальные блоки таким образом, чтобы я не получил срыв / разрыв. Кроме того, когда загружается новый файл, чтение не обязательно начинается.

У меня есть несколько мыслей:

  1. Можем ли мы предварительно извлечь файлы в кэш, прочитав их все один раз при запуске, но игнорируя данные? Я не могу хранить все это в памяти. Но кажется плохим полагаться на внутреннее поведение кеша чтения ОС, тем более что это кроссплатформенность.

  2. Можем ли мы использовать такой формат, как Ogg Vorbis для сжатия, полностью загрузить сжатые данные в память и затем декодировать на лету? Я думаю, что декодирование 10 или более потоков Vorbis может быть слишком загруженным процессором, но у меня пока нет тестов. По крайней мере, таким образом мы превращаем ее из задачи, связанной с вводом / выводом, в задачу, связанную с процессором.

  3. Можем ли мы сделать какой-либо другой разумный подход к буферизации, чтобы сделать так, чтобы большие чтения были более равномерно распределены? Я очень мало знаю о том, как мне этого добиться.

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

2

Решение

Попробуйте выполнить загрузку файла, используя обработку событий.

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

Наиболее широко доступный API для этого с «select» (http://linux.die.net/man/2/select), но есть лучшие методы (опрос, epoll, kqueue). Они не доступны везде.

Есть библиотеки, которые абстрагируют это для вас (libev и libevent).

Так что, как вы это делаете, один поток открывает все нужные вам файлы и устанавливает для них «наблюдатель». Когда данные доступны, наблюдатель срабатывает и вызывает обратный вызов.

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

1

Другие решения

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

0

По вопросам рекламы [email protected]