python-zstandard

repository·main·Indexed 20 days ago

https://github.com/indygreg/python-zstandard

High-performance Python bindings for the Zstandard compression library (version 0.25.0). It provides both C extension and CFFI interfaces, offering one-shot and streaming APIs for compression and decompression. The library includes features for dictionary compression, custom buffer types for efficient memory management, and fine-grained control via ZstdCompressionParameters.

Tokens
16.4K
Snippets
50
Records
80
Agent score
70%

What's inside python-zstandard

  1. Overview of python-zstandard

    main
    python-zstandard provides Python bindings for the Zstandard compression library. It offers both a C extension and a CFFI interface. The library is designed to provide a rich, Pythonic interface to the underlying Zstandard C API, balancing high performance with the usability and safety expected in Python.
  2. Understand the project status and stability

    main

    The project is currently in beta. Users should expect potential backwards incompatible changes before version 1.0 (likely in the 0.9 release), such as renaming the main module from zstd to zstandard and renaming various types and methods.

    Best Practice: Pin your package version to prevent unwanted breakage when these changes occur.

    Supported platforms include Linux x86_x64 and Windows x86/x86_64 (Python 3.10+). The library provides both C extension and CFFI implementations, with the CFFI bindings being mostly feature complete.

  3. Supported types via the Python Buffer Protocol

    main

    Many functions in python-zstandard accept any Python object that implements the buffer protocol. This allows the library to access the raw bytes of an object without requiring explicit conversion to bytes first.

    Supported types include:

    • bytes
    • bytearray
    • array.array
    • io.BytesIO
    • mmap.mmap
    • memoryview
  4. Performance characteristics and tuning

    main

    Zstandard is highly tunable. Performance characteristics depend on the settings used:

    • Default (Level 3): Generally faster and provides better compression ratios than zlib on most datasets.
    • Speed-tuned: Approaches lz4 speed and ratios.
    • Ratio-tuned: Approaches lzma ratios and compression speed, but with much faster decompression.

    Key Performance Features:

    • Multi-threading: Supports multi-threaded compression for large inputs.
    • Zero-copy: The library provides multiple APIs to facilitate zero-copy operations and minimize Python object creation/garbage collection overhead.
    • Throughput: Capable of single-threaded throughputs exceeding 1 GB/s.

    To measure performance on your specific hardware, use the bench.py script found in the source code repository.

  5. Decompression requirements for output sizes

    main

    When using one-shot (non-streaming) decompression APIs, you must provide a way to determine the output size. This is because the API requires a pre-allocated buffer to store the result.

    To decompress, you must either:

    1. Ensure the zstd frame header contains the decompressed size.
    2. Explicitly pass the required output size to the function.
    3. Specify a maximum output size.

    Security Note: The library limits the maximum output size to prevent 'decompression bombs' (e.g., a small input that expands to many gigabytes), which could otherwise exhaust system memory.

  6. Understand Zstandard Frames and Content Size

    main

    Zstandard data is contained within a frame, which includes a header and an optional trailer. The header identifies the data as a zstd frame and describes the compressed content.

    To optimize decompression performance, you should store the original content size within the frame. This allows the decompressor to perform a single, exact memory allocation for the output rather than repeatedly growing a buffer.

    In python-zstandard, you can enable this by setting write_content_size=True when initializing a ZstdCompressor.

    # Example of enabling content size writing for better decompression performance
    compressor = zstd.ZstdCompressor(write_content_size=True)
  7. Using Dictionaries for better compression

    main

    A compression dictionary is used to seed the compressor state with common patterns found in your data. This is highly effective when compressing many small, similar objects (e.g., JSON documents with the same structure).

    When to use: Dictionary compression is generally only beneficial for small inputs, typically data no larger than a few kilobytes. The effectiveness depends on the similarity between your data and the dictionary used.

  8. Thread and object reuse safety rules

    main

    To avoid race conditions and crashes, follow these safety guidelines:

    1. No Overlapping Operations: A single ZstdCompressor or ZstdDecompressor instance (and any objects derived from them, like ZstdCompressionReader) cannot be used for multiple overlapping operations. You must finish one operation before starting another on the same instance.
    2. No Simultaneous Thread Access: Do not use the same ZstdCompressor or ZstdDecompressor instance in different threads at the same time.
    3. Parallelism via Multiple Instances: If you need to perform multiple compression/decompression tasks in parallel, you must create a separate ZstdCompressor or ZstdDecompressor instance for each thread/task.
    4. Read-Only Assumption: When passing mutable bytes-like objects (e.g., bytearray) to compression methods, ensure they are not mutated by another thread while the function is running, as the C extension may release the GIL during the operation.
  9. Note on Zstandard's experimental API

    main

    Many APIs used by this module are marked as experimental within the upstream Zstandard project (e.g., dictionary training).

    Because the Zstandard C API's evolution for experimental features is uncertain, the behavior of the underlying C API might change. However, python-zstandard mitigates this by vendoring and statically linking a specific version of the Zstandard source code. This ensures that the behavior of a specific version of python-zstandard remains constant.

    Recommendation: Pin your version of python-zstandard to ensure consistent behavior and protection from upstream changes.

  10. How Compression and Decompression Contexts work

    main

    A context holds the configuration (like compression level) and the state for a zstd operation. In this library, ZstdCompressor and ZstdDecompressor act as wrappers around these C API contexts.

    Performance Tip: Creating and destroying contexts is computationally expensive. You should reuse ZstdCompressor and ZstdDecompressor instances for multiple operations to gain performance advantages.

  11. One-shot vs. Streaming Operations

    main

    You can perform compression and decompression using two different modes:

    1. One-shot (Simple APIs): All input is provided as a single buffer, and the entire output is returned as a single buffer. This is the simplest way to use the library for data that fits comfortably in memory.
    2. Streaming: Input and output are handled in chunks via multiple function calls. This requires a stream object (a logical extension of a context) to track the state of the ongoing operation. Streaming is necessary for processing data that is too large to fit in memory at once.
  12. How to choose between One-Shot and Streaming APIs

    main

    The library provides two main categories of APIs depending on your data size and memory constraints:

    One-Shot APIs

    • Best for: Small data where the input and output sizes are known.
    • Pros: Simple to use (single function call).
    • Cons: Both input and output must fit in memory simultaneously. Large inputs can cause long blocking operations.

    Streaming APIs

    • Best for: Large datasets or data arriving in chunks.
    • Pros: Does not require all data to be in memory at once; provides fine-grained control over input/output flow.
    • Cons: More complex to implement than one-shot calls.
    • Note: When using streaming APIs with file-like or stream objects, be aware that I/O operations (like network or disk access) can cause long pauses in the execution flow.