Pigz - kompresja wielowątkowa

Narzędzia do pakowania danych w systemach Linux takie jak gzip, xz, bzip2, brotli stosują kilka głównych algorytmów do kompresji danych oraz mnóstwo wariacji i ulepszeń, które mają za zadnie zwiekszyć stopień kompresji albo skrócić czas działania. Wspólną cechą tych narzędzi jest to, że działają jednowątkowo, wykorzystując jedne rdzeń procesora. Powoduje to, że chcąc przyspieszyć działania takich programów poprze możliwości sprzętowe, możemy jedynie zwiększać taktowanie procesora aby to uzyskać.

Istnieje jednak zupełnie inne rozwiązanie. Kompresję można przyspieszyć poprzez podzielenie danych na mniejsze pakiety i rozdzielenie zadań kompresji na kilka rdzeni procesora, tak aby wykonały się równolegle. W teorii pozwala to przyspaieszyć pakowanie nawet tyle razy ile mamy do dyspozycji rdzeni procesora. Biorąc pod uwagę, że obecnie (styczeń 2026) nawet w laptopach dostępne jest 4-8 rdzeni, a w stacjach roboczych czy serwerach możemy mieć od 16 do ponad 100 rdzeni, to warto zastanowić się nad takim rozwiązaniem, szczególnie gdy mamy do pakowania większe zbiory danych.

Jednym z narzędzi które oferuje wielowątkową równoległą kompresję danych jest polecenie pigz.

pigz można opisać jako wielowątkową wersję programu gzip. pigz używa tego samego algorytmu - Deflate - co gzip oraz generuje pliki w formacie .gz w pełnie zgodne z gzip. Działa poprzez podzielenie danych wejściowych na bloki po 128 kB (lub o innym, zadanym rozmiarze), kompresję ich w wielu wątkach, a następnie odpowienio je oznacza i szereguje w pliku wyjściowym. pigz może używać zadanej liczby wątków lub też wykrywać automatycznie dostępne rdzenie (procesory).

pigz stosuje podobne opcje i przełączniki wiersza poleceń jak gzip, tzn można wybrać zadany stopień kompresji (-#). Standarowa jest opcja rozpakowania (-d) oraz opcje zachowania czasów modyfikacji plików. Domyślne działanie z plikiekm jest też takie jak w gzip - tworzony jest plik spakowany z rozszerzeniem .gz, a plik wejściowy jest usuwany.

Główna różnica w stosunku do "tradycyjnego" gzipa to opcja -p pozwalająca wskazać ile rdzeni program ma użyć do pracy z kompresją. Domyślne zachowanie to użycie wszystkich dostępnych rdzeni, lub 8 wątków, jeśli nie można wykryć rdzeni. Wartość -p 1 wyłącza kompresję wielowątkową.

Przykład:

$ pigz  -p 12 bigdata

pigz wykona kompresję z użyciem 8 rdzeni.

Przyjrzymy się jak działa przyspieszenie wielowątkowe w pigz. Wykonajmy test polegajcy na kompresji tych samych danych z różną liczbą wątków.

Maszyny, system operacyjny i wersje pigz użyte w tym teście:

Test przeprowadzimy na zbiorze danych z projektu Prague Corpus Jest to archiwum tar (niskompresowane) zawierające około 30 plików różnych rodzajów (m.in. dźwięk, obraz, dokumenty, tekst, kody źródłowe, tabele danych) Maszyna, na której testowano:

Wersja pigz: 2.4

Testy przeprowadzono w urządzeniu /dev/shm, aby wyeliminować maksymalnie wpływ prędkości pamięci masowej na wyniki.

Schemat testu był następujący:

cd /dev/shm/test;
cp $start_dir/PragueCorpus.tar .
isize=$(stat --printf="%s" "PragueCorpus.tar")

/usr/bin/time -f "$e" -f time_file pigz -p $nproc PragueCorpus.tar

osize=$(stat --printf="%s" "PragueCorpus.tar.gz")
ctime=$(cat time_file)
/usr/bin/time -f "$e" -f time_file pigz -p $nproc -d PragueCorpus.tar.gz
dtime=$(cat time_file)
echo pigz $ctime $dtime $isize $osize $nproc

Z uzyskanych danych obliczamy stopień kompresji dzieląc wartości isize przez osize, oraz przyspieszenie dzieląc czas kompresji dla danej liczby wątków przez czas dla jednego wątku.

Wyniki wyglądają następująco:

Liczba wątków Czas kompresji Czas dekompresji Stopień kompresji Przyspieszenie
1.00 2.68 0.30 1.60 1.00
2.00 1.37 0.25 1.60 1.96
3.00 0.91 0.25 1.60 2.95
4.00 0.69 0.25 1.60 3.88
5.00 0.55 0.25 1.60 4.87
6.00 0.47 0.25 1.60 5.70
7.00 0.40 0.25 1.60 6.70
8.00 0.35 0.25 1.60 7.66
9.00 0.32 0.25 1.60 8.38
10.00 0.28 0.25 1.60 9.57
11.00 0.26 0.25 1.60 10.31
12.00 0.24 0.25 1.60 11.17
13.00 0.23 0.25 1.60 11.65
14.00 0.21 0.25 1.60 12.76
15.00 0.20 0.25 1.60 13.40
16.00 0.19 0.25 1.60 14.11
17.00 0.18 0.25 1.60 14.89
18.00 0.17 0.25 1.60 15.76
19.00 0.16 0.25 1.60 16.75
20.00 0.16 0.25 1.60 16.75
21.00 0.15 0.25 1.60 17.87
22.00 0.15 0.25 1.60 17.87
23.00 0.14 0.25 1.60 19.14
24.00 0.14 0.25 1.60 19.14
25.00 0.13 0.25 1.60 20.62
26.00 0.13 0.25 1.60 20.62
27.00 0.13 0.25 1.60 20.62
28.00 0.13 0.25 1.60 20.62
29.00 0.13 0.25 1.60 20.62
30.00 0.12 0.25 1.60 22.33
31.00 0.12 0.25 1.60 22.33
32.00 0.12 0.25 1.60 22.33
33.00 0.12 0.25 1.60 22.33
34.00 0.12 0.25 1.60 22.33
35.00 0.11 0.25 1.60 24.36
36.00 0.11 0.25 1.60 24.36
37.00 0.11 0.25 1.60 24.36
38.00 0.11 0.25 1.60 24.36
39.00 0.11 0.25 1.60 24.36
40.00 0.11 0.25 1.60 24.36
41.00 0.11 0.25 1.60 24.36
42.00 0.11 0.25 1.60 24.36
43.00 0.11 0.25 1.60 24.36
44.00 0.11 0.25 1.60 24.36
45.00 0.11 0.25 1.60 24.36
46.00 0.11 0.25 1.60 24.36
47.00 0.11 0.25 1.60 24.36
48.00 0.11 0.25 1.60 24.36

Jak widać, problem czasu kompresji się zmniejsza - do pewnego momentu, czas dekompresji i stopień pozstaje stały, przyspieszenie jest widczone.

Przyjżyjmy się wynikom dokładniej za pomocą wykresu

Przyspieszenie kompresji

Widać, że przyspieszenie kompresji jest wyraźne w zakresie od 2 do około 26 rdzeni. Powyżej tej liczby przyspieszenie nie rośnie już znacząco, uzyskuje maksimum przy około 35 rdzeniach. Do około 12 rdzeni przyspieszenie jest niemal liniowo proporcjonlane do liczby użytych wątków (zielona linia), powyżej tej wartości zaczyna co raz bardziej odstawać, aby przy około 35 rdzeniach przestać całkowicie rosnąć.

Przyczyny takiego zachowania mogą być różne: rodzielanie zadań przez program, zapisywanie danych do pliku, sposób pracy maszyny z dwoma dwurdzeniowymi procesorami, dynamiczne zmiany w taktowaniu procesora w zależności od obciążenia. W tym artykule nie wyjaśnimy tego do końca. Są to jednak zjawiska znane z działania programów równoległych.

Poodkreślmy jednak, że uzyskaliśmy ponad 20-krotne skrócenie czasu kompresji danych.

Warto jeszcze wspomnieć o czasie wypakowania. Jak widać w tabeli, nie ma tu tak zanczącego przyspieszenia, a właściwie jest tylko pewien przeskok międzu jednym a wieloma wątkami. Dzieje się tak ponieważ, pigz musi wypakować i zapisać dane w odpowiedniej kolejności i nie można tego zrównoleglić. Jeśli przy dekompresji jest dostępne więcej niż jeden rdzeń, pigz, tworzy jeden wątek dekompresji i trzy pomocnicze wątki do odczytu, zapisu i werfikacji danych.

Podsumowanie

Poznaliśmy funkcję programu do kompresji danych polegająca na wykorzystaniu procesora wielordzeniowego do przyspieszenia kompresji danych.

Nauczyliśmy się, że warto czasem poszukać alternatywnego rozwiązania (pigz) dla znanego narzędzia (gzip), bo może ono oferwać lepsze funkcjie niż orginał.

Warto analizować działanie programów na konkretnych danych, zawłaszcza tych które wymagają pewnych nieco większych zasobów komputera, czy też czasu pracy procesora.

Program pigz.

Strona domowa: https://zlib.net/pigz/

Licencja: Licenzja zlib (wolne oprogramowanie)

benchmark desktop linux polecenia serwer terminal