10

У меня есть несколько файлов JSON по 20 ГБ каждый, которые я хочу сжать с помощью gzip:

gzip file1.json

Это занимает одно полное ядро процессора, все хорошо.

Он обрабатывает около 25 МБ / с (проверено atop), мой жесткий диск может читать 125 МБ / с, и у меня есть 3 свободных процессорных ядра, поэтому я ожидаю ускорения при сжатии нескольких файлов параллельно. Итак, я бегу в других терминалах:

gzip file2.json
gzip file3.json
gzip file4.json

Удивительно, но моя пропускная способность не увеличивается; Процессор составляет около 25% на каждое ядро, а мой HD все еще читает только со скоростью 25 МБ / с.

Почему и как это решить?

3 ответа3

15

Я узнал это:

Причина в том, что gzip работает (с точки зрения скорости процессора и скорости поиска HD в наши дни) очень низких размеров буфера.

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

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


Я обошел это, используя утилиту buffer unix:

buffer -s 100000 -m 10000000 -p 100 < file1.json | gzip > file1.json.gz

Буферизуя большую часть ввода перед отправкой в gzip, количество маленьких запросов может быть значительно уменьшено. Варианты:

  • -s и -m указывают размер буфера (я думаю, что это в КБ, но не уверен)
  • -p 100 гарантирует, что данные передаются в gzip только после заполнения буфера на 100%

Запустив четыре из них параллельно, я мог получить пропускную способность 4 * 25 МБ / с, как и ожидалось.


Мне все еще интересно, почему gzip не позволяет увеличивать размер буфера - таким образом, он довольно бесполезен, если он запускается на вращающемся диске.

РЕДАКТИРОВАТЬ: я опробовал еще несколько программ сжатия поведения:

  • bzip2 обрабатывает только 2 МБ / с из-за более сильного / более интенсивного сжатия процессора
  • Похоже, что lzop допускает большие буферы: 70 МБ / с на ядро, а 2 ядра могут максимально использовать мой HD без чрезмерного поиска
3

Посмотрев первые пять или около того лекций в MIT OpenCourseware для 6.172: "Проектирование производительности программных систем", я запустил анализатор производительности Linux "perf" на умеренно большом тестовом файле. Результат, по-видимому, показывает конвейерные остановки, где одна инструкция должна ждать результата предыдущей.

       │         while (lookahead != 0) {                                                                
       │             /* Insert the string window[strstart .. strstart+2] in the                          
       │              * dictionary, and set hash_head to the head of the hash chain:                     
       │              */                                                                                 
       │             INSERT_STRING(strstart, hash_head);                                                 
  2.07 │       movzbl 0x8096d82(%edx),%eax                                                               
  3.99 │       mov    %edx,%ebp                                                                          
       │       shl    $0x5,%ecx                                                                          
  0.03 │       and    $0x7fff,%ebp                                                                       
  1.94 │       xor    %ecx,%eax                                                                          
  1.43 │       and    $0x7fff,%eax                                                                       
  2.01 │       mov    %eax,0x805e588                                                                     
  2.40 │       add    $0x8000,%eax                                                                      
  0.88 │       movzwl 0x8062140(%eax,%eax,1),%ecx                                                        
 23.79 │       movzwl %cx,%edi                                                                           
       │             /* Find the longest match, discarding those <= prev_length.  

Вторая последняя инструкция копирует в %ecx и последняя должна ждать (останавливая конвейер), пока регистр %cx не будет готов к использованию. Этот трубопроводный трубопровод задерживает вмещающую петлю.

Это результат какого-то действительно неясного стиля программирования на языке С.

1

Совет, который может привести к еще одному уровню скорости на многоядерном / гиперпоточном процессоре:
(предполагая Ubuntu)

sudo apt-get установить moreutils

Moreutils содержит, помимо прочего, "gnu parallel", которая имеет много опций, помогающих использовать больше вашего процессора.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .