многопоточность — C ++ / C Несколько потоков для чтения файла gz одновременно

Я пытаюсь прочитать сжатый gzip файл из нескольких потоков.

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

Упрощенный код похож на

// in threads
auto gf = gzopen("file.gz",xxx);
gzseek(gf,offset);
gzread(xx);
gzclose(gf);

К моему удивлению, моя многопоточная версия программы не ускорить на всех. Версия с 20 потоками использует то же самое время, что и версия с одним потоком. Я почти уверен, что это далеко от узкого места на диске.

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

Кто-нибудь есть идеи, как ускорить в моем случае?

3

Решение

tl; dr: zlib не предназначен для произвольного доступа. Кажется возможным реализовать, хотя для создания индекса требуется полное прочтение, поэтому в вашем случае это может оказаться бесполезным.

Давайте посмотрим на источник zlib. gzseek это обертка вокруг gzseek64, который содержит:

/* if within raw area while reading, just go there */
if (state->mode == GZ_READ && state->how == COPY &&
state->x.pos + offset >= 0) {

«Внутри необработанной области» звучит не совсем правильно, если мы обрабатываем сжатый файл. Давайте посмотрим на значение state->how в gzguts.h:

int how; /* 0: get header, 1: copy, 2: decompress */

Правильно. В конце gz_openвызов gz_reset наборы how на 0. Возвращаясь к gzseek64в итоге мы получим эту модификацию состояния:

state->seek = 1;
state->skip = offset;

gzread, когда вызывается, обрабатывает это с вызовом gz_skip:

if (state->seek) {
state->seek = 0;
if (gz_skip(state, state->skip) == -1)
return -1;
}

Следуя этой кроличьей норе чуть дальше, мы обнаруживаем, что gz_skip звонки gz_fetch до тех пор gz_fetch обработал достаточно ввода для желаемого поиска. gz_fetchв своей первой итерации цикла вызывает gz_look который устанавливает state->how = GZIP, что приводит к gz_fetch распаковать данные из ввода. Другими словами, ваше подозрение верно: zlib распаковывает весь файл до того момента, когда вы используете gzseek,

1

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

Краткий ответ: из-за серийного характера потока дефлята, gzseek() должен декодировать все сжатые данные от начала до запрошенной точки поиска. Таким образом, вы не можете получить никакой выгоды от того, что вы пытаетесь сделать. Фактически, общее количество потраченных циклов будет увеличиваться с квадратом длины сжатых данных! Так что не делай этого.

4

В реализации zlib нет многопоточности (http://www.zlib.net/zlib_faq.html#faq21 — «Является ли zlib потокобезопасным? — Да. … Конечно, вы должны работать только с любым потоком zlib или gzip из одного потока за раз.») И распакует «весь файл» до искомой позиции.

И формат zlib имеет плохое выравнивание (битовое выравнивание) / нет смещенных полей (формат выкачки) включить параллельную декомпрессию / поиск.

Вы можете попробовать другие реализации z (deflate / inflate), например, http://zlib.net/pigz/ (или перейдите от древней компрессии из эпохи одноядерных к современным параллельным форматам без zlib, xz / lzma / что-то из Google)

pigz, который означает параллельную реализацию gzip, является полностью функциональной заменой gzip, которая использует несколько процессоров и несколько ядер для сжатия при сжатии данных. pigz был написан Марком Адлером и использует библиотеки zlib и pthread. Чтобы скомпилировать и использовать pigz, пожалуйста, прочитайте файл README в дистрибутиве исходного кода. Вы можете прочитать страница руководства pigz здесь.

Страница руководства http://zlib.net/pigz/pigz.pdf и у него есть полезная информация.

Он использует формат, совместимый с zlib, но адаптированный для параллельного сжатия:

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

Тем не менее, формат DEFLATE плох для параллельной распаковки:

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

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector