Hands-on zlib.compress vs gzip.compress same-level (6) stdlib bake-off: real MB/s and sizes, measured on Linux localhost in this hands-on lab for SREs.
4 min read
In-memory compress/decompress of a compressible fixture via zlib.compress / zlib.decompress vs gzip.compress / gzip.decompress at the same level (6). This lab reports MB/s and output size on Linux localhost.
It is not the multi-codec zstd/gzip/lz4 bake-off (lab 33) and not nginx gzip toggles (lab 20). Here the question is only: Python stdlib zlib vs gzip wrappers.
Related links:
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. No Docker. Level 6. Fixture = repeating JSON-ish lines (highly compressible).
Verdict up front (1 MiB): gzip.compress ~335.4 MB/s (out 3661 B); zlib.compress ~320.0 MB/s (out 3649 B); decompress gzip ~994.4 / zlib ~905.3 MB/s. Gzip adds a fixed ~12 B header/trailer overhead on this box.
| Arm | API |
|---|---|
zlib.compress(data, 6) | raw DEFLATE container |
gzip.compress(data, compresslevel=6) | gzip framing around zlib |
zlib.decompress / gzip.decompress | matching decode |
Script: lab-evidence/102-zlib-vs-gzip-compress/results/run_lab.py.
| Arm | MB/s | out bytes | ratio |
|---|---|---|---|
| gzip.compress | 335.4 | 3661 | 0.0035 |
| zlib.compress | 320.0 | 3649 | 0.0035 |
| gzip.decompress | 994.4 | — | — |
| zlib.decompress | 905.3 | — | — |
Gzip overhead vs zlib blob: 12 bytes (header + CRC trailer). Throughput is in the same ballpark — framing cost is tiny next to DEFLATE work.
| Size | zlib | gzip | overhead B |
|---|---|---|---|
| 256 KiB | 330.3 | 343.8 | 12 |
| 1 MiB | 320.0 | 335.4 | 12 |
| 4 MiB | 306.7 | 319.9 | 12 |
gzip.compress is zlib DEFLATE plus a gzip header and CRC32/ISIZE trailer. Use gzip when peers expect .gz / HTTP Content-Encoding: gzip. Use raw zlib (or raw DEFLATE) when you own both ends and want a smaller envelope (e.g. some wire protocols).
This lab uses one-shot compress/decompress on full buffers. Chunked compressobj / GzipFile changes memory profile and can change throughput — re-measure if your pipeline is streaming.
Always pin the same compresslevel (here 6, zlib/gzip default band). Comparing zlib-1 to gzip-9 is a common blog mistake and says nothing useful about framing overhead.
HTTP Content-Encoding: gzip, .gz files on disk, and many CLIs speak gzip. Some databases and custom RPCs prefer zlib or raw DEFLATE. Matching the peer’s expected magic bytes matters more than the ~tens of MB/s delta on this box.
Evidence: summary.json, summary.txt.
One Linux box. Synthetic repeating JSON lines (very compressible). Level fixed at 6. Not streaming zlib.compressobj / GzipFile chunked APIs.
At 1 MiB level 6, gzip.compress ~335.4 MB/s and zlib.compress ~320.0 MB/s — choose gzip for interoperability, zlib for a leaner envelope (+12 B for gzip here).
Lab evidence
Lab 1 Oct 2026 IST. Python 3.13.5. level=6. 1MiB: gzip_compress 335.4 MB/s out=3661; zlib_compress 320.0 out=3649; overhead 12B. Not lab 33 multi-codec / lab 20 nginx. Affiliates: 0. Evidence: lab-evidence/102-zlib-vs-gzip-compress/.
Hands-on mmap MAP_SHARED write+msync vs pwrite region update: real MB/s with durability labels, measured on Linux localhost in this hands-on lab for SREs.
Lab1 Oct 20264 min read
Hands-on itertools.islice vs list slice window lab: real ops/s taking ranges from sequences, measured on Linux localhost in this hands-on lab for SREs.
Lab1 Oct 20264 min read
Hands-on heapq.merge vs sorted(chain) multi-way merge: real records/s on pre-sorted lists, measured on Linux localhost today in this hands-on lab for SREs.
Lab1 Oct 20264 min read