Repository navigation
Conversation
When nthreads is given, decompress calls blosc_decompress_ctx with that many threads. It does not use Blosc's global context or _MUTEX and ignores use_threads. The default (None) leaves the behavior unchanged. Values outside 1 to MAX_THREADS raise ValueError.
Same behavior as for decompress: when nthreads is given, compress calls blosc_compress_ctx with that many threads, without Blosc's global context or _MUTEX, and ignores use_threads. For a buffer of several blocks and nthreads above 1 the compressed bytes can differ between calls (the blocks can appear in a different order); the decompressed data is the same.
Contributor
|
this is cool, and I don't think we are worried about the flaky byte representation. We just need to document what's constant, and what's not. |
Zappandy
marked this pull request as ready for review
October 23, 2026 14:34
mkitti
reviewed
Oct 23, 2026
Say how the number of threads is chosen when nthreads is None, and which properties of the compressed output stay the same when nthreads is above 1.
There was a problem hiding this comment.
🟢 Approval recommended
No blocking issues remain; the retained feedback is a minor clarification of fork-related documentation.
1 open issue
What changed in this PR
This PR adds per-call thread control to Blosc compression and decompression, allowing callers to request multiple threads even when global threading is disabled, while preserving existing defaults.
Changes:
- Add validated optional
nthreadsarguments that select Blosc’s context functions. - Add coverage for round trips, destination buffers, invalid values, global-state isolation, concurrency, and forked workers.
- Document the new arguments and announce them in the release notes.
| File | Description |
|---|---|
tests/test_blosc.py |
Tests explicit thread counts and compatibility with existing behavior. |
src/numcodecs/blosc.pyx |
Adds argument validation, context dispatch, and API documentation. |
docs/release.md |
Announces optional per-call thread control. |
Review effort: Balanced
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #882 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 27 27
Lines 914 914
=========================================
Hits 914 914 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Related: zarr-developers/zarr-python#4531.
Problem description
zarr-python 3 sets
numcodecs.blosc.use_threads = Falseon import, soblosc.decompresscallsblosc_decompress_ctx(..., 1)and one large chunk is decoded on one thread (zarr-developers/zarr-python#4531). Zarr maintainers suggested an integernthreadsargument passed to the_ctxfunctions.I'm passing
nthreads:compress(source, cname, clevel, ..., nthreads=None)anddecompress(source, dest=None, nthreads=None). WithNonethe number of threads is set as before, byuse_threadsandset_nthreads. An integer from 1 toMAX_THREADSmakes the call useblosc_compress_ctxorblosc_decompress_ctxwith that many threads, without_MUTEXor the global context. Other values raiseValueError.I put a small script that times both functions for different block counts and thread counts in a gist: https://gist.github.com/Zappandy/6975e3231a64068ad541e47ea1331b5f
About
compressI've a separate commit for this one in case you guys prefer i roll it back. With
nthreadsgreater than 1, compressing a buffer of several blocks can give different bytes between calls. THat being said, I compressed the same buffer 300 times: each block had the same bytes in every run, only the order of the blocks in the buffer changed, and the decoded data was the same.nthreads=1gave the same bytes every time. I saw the same withuse_threads=Trueandset_nthreads(8), and the default (use_threads=None) also uses Blosc threads when called from the main thread (_get_use_threadsinblosc.pyx).Version and installation information
numcodecs.__version__: 0.17.1 (main), c-blosc 1.21.7.devPython 3.12.13
Linux; built from source with meson-python
TODO:
Unit tests and/or doctests in docstrings
Tests pass locally
Docstrings and API docs for any new/modified user-facing classes and functions
Changes documented in docs/release.rst
Docs build locally
GitHub Actions CI passes
Test coverage to 100% (Codecov passes)
Codevoc doesn't measure .pyx files