Exemplo
joblib 1.5.3: Configure joblib parallel execution with parallel_config and verify backend constraint resolution, nested context propagation, and failure modes on contradictory settings.
Amostra verificada para pypi joblib 1.5.3: Configure joblib parallel execution with parallel_config and verify backend constraint resolution, nested context…
sha256:358ff91d26968481475e6fb33480225b3c25f6adba6d6bb2170118ee39c4a2de
Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu.
Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas.
MIT-0
Evidência de execução
O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.
- Base da evidência
- Contrato assinado aprovado
- Recibos de verificação
- 3
- Chaves de assinatura que o compilaram
- 3
Ambiente declarado
python linux x64 python python pip
Ambientes das execuções de verificação
| Ambiente | Contrato | Etapas | Execução |
|---|---|---|---|
| python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-19 |
| python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-19 |
| python 3.12 · linux debian/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1python:3.12-slim@sha256:09f7da3bc104… |
2026-09-07 |
Caso
HOW- Objetivo
- Configure joblib parallel execution with parallel_config and verify backend constraint resolution, nested context propagation, and failure modes on contradictory settings.
- Pacotes
- Símbolos
-
- joblib.parallel_config
- joblib.Parallel
- joblib.delayed
- joblib.parallel.get_active_backend
- Ambiente
- python
- Criado
- 2026-08-19T13:42:06Z
Contrato
- Setting prefer='threads' in parallel_config with n_jobs=4 switches to ThreadingBackend but silently resets implicit n_jobs in context to 1, while explicit backend='threading' preserves n_jobs=4.
- Explicitly passing n_jobs=4 to Parallel overrides the thread fallback reset back to 4.
- Setting require='sharedmem' without an explicit backend forces ThreadingBackend and resets implicit n_jobs to 1.
- Contradictory settings prefer='processes' and require='sharedmem' raise ValueError on Parallel instantiation.
- Instantiating Parallel(backend='multiprocessing', require='sharedmem') raises ValueError, whereas configuring the same settings under parallel_config silently downgrades to ThreadingBackend and resets n_jobs to 1.
- Nested parallel_config scopes override configuration parameters within their block and restore outer context settings upon exit.
- Passing backend constructor parameters such as inner_max_num_threads without an explicit backend raises ValueError at context entry.
- Passing an unregistered backend name to parallel_config raises ValueError immediately at context entry.
Arquivos
- NOTES.md
- csx.json
- requirements.txt
- test/contract.py
Código-fonte
# Joblib parallel_config Backend Resolution and Fallback
`search_known_solution` returned existing compatible samples `sha256:8975a821537b8b2bb33e76eda5c67597b978a25b160ca5e58f4a872aabeb41fa` (covering memory mapping compression tradeoffs) and `sha256:7786cfc40f400486765033eec7c04f3a21347d8f8513d308a4911a5ce6363569` (covering closure serialization across execution backends). This sample targets configuration behavior and backend constraints in `joblib.parallel_config`.
## Pinned Release
- `joblib==1.5.3`
## Observed Behavior
1. **Silent Fallback to Single Worker (`n_jobs=1`)**: When using `parallel_config(n_jobs=4, prefer="threads")` or `parallel_config(n_jobs=4, require="sharedmem")` without specifying an explicit `backend="threading"`, Joblib activates `ThreadingBackend` but its backend resolver applies a safety heuristic that resets the context's effective `n_jobs` to `1`. Consequently, unparameterized `Parallel()` constructor calls inside that context run tasks sequentially on a single thread rather than across 4 concurrent threads.
2. **Explicit Backend Preserves Worker Count**: Configuring `parallel_config(n_jobs=4, backend="threading")` or explicitly instantiating `Parallel(n_jobs=4)` preserves `n_jobs=4`.
3. **Contradictory Settings Failure**: Specifying `prefer="processes"` with `require="sharedmem"` in `parallel_config` raises `ValueError: prefer == 'processes' and require == 'sharedmem' are inconsistent settings` when `Parallel()` is constructed.
4. **Context Manager vs Direct Constructor Contrast**: Instantiating `Parallel(backend="multiprocessing", require="sharedmem")` raises `ValueError: Backend <MultiprocessingBackend ...> does not support shared memory`, whereas setting `parallel_config(backend="multiprocessing", require="sharedmem")` intercepts the unsupported combination, automatically downgrades to `ThreadingBackend`, and resets `n_jobs` to `1`.
5. **Backend Constructor Arguments**: Supplying backend-specific constructor arguments such as `inner_max_num_threads` to `parallel_config` without specifying an explicit `backend` raises `ValueError` at context entry.
6. **Unregistered Backends**: Passing an unregistered backend identifier (such as `backend="nonexistent"`) to `parallel_config` raises `ValueError` immediately at context entry.
## Failure Modes
- **Silently**: `parallel_config(n_jobs=4, prefer="threads")` produces a green build while tasks execute serially with `n_jobs=1` instead of parallel execution across 4 worker threads.
- **Loudly**: Conflicting constraints (`prefer="processes"` and `require="sharedmem"`) or configuring `inner_max_num_threads` without setting `backend` raises `ValueError`.
{"case":{"believed":"Configuring parallel_config with prefer='threads' and n_jobs=4 executes subsequent unparameterized Parallel calls across 4 worker threads.","caseId":"case:sha256:beab5c697cc7313f26e2fe0f3b590f3e13284a2b9ab5765b9fb1c3918f8790ab","contract":["Setting prefer='threads' in parallel_config with n_jobs=4 switches to ThreadingBackend but silently resets implicit n_jobs in context to 1, while explicit backend='threading' preserves n_jobs=4.","Explicitly passing n_jobs=4 to Parallel overrides the thread fallback reset back to 4.","Setting require='sharedmem' without an explicit backend forces ThreadingBackend and resets implicit n_jobs to 1.","Contradictory settings prefer='processes' and require='sharedmem' raise ValueError on Parallel instantiation.","Instantiating Parallel(backend='multiprocessing', require='sharedmem') raises ValueError, whereas configuring the same settings under parallel_config silently downgrades to ThreadingBackend and resets n_jobs to 1.","Nested parallel_config scopes override configuration parameters within their block and restore outer context settings upon exit.","Passing backend constructor parameters such as inner_max_num_threads without an explicit backend raises ValueError at context entry.","Passing an unregistered backend name to parallel_config raises ValueError immediately at context entry."],"goal":"Configure joblib parallel execution with parallel_config and verify backend constraint resolution, nested context propagation, and failure modes on contradictory settings.","kind":"HOW","packages":["pkg:pypi/joblib@1.5.3"],"schemaVersion":1,"symbols":["joblib.parallel_config","joblib.Parallel","joblib.delayed","joblib.parallel.get_active_backend"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/joblib@1.5.3"],"schemaVersion":1,"symbols":["joblib.parallel_config","joblib.Parallel","joblib.delayed","joblib.parallel.get_active_backend"],"verifierAdapter":"python@1"}
joblib==1.5.3
from joblib import Parallel, delayed, parallel_config
import joblib.parallel as jp
from joblib._parallel_backends import ThreadingBackend, LokyBackend
def main():
# 1. prefer="threads" selects ThreadingBackend but silently resets implicit n_jobs in context to 1
with parallel_config(n_jobs=4, prefer="threads"):
p_implicit = Parallel()
assert isinstance(p_implicit._backend, ThreadingBackend)
assert p_implicit.n_jobs == 1
# Explicit n_jobs in Parallel constructor overrides the fallback reset
p_explicit = Parallel(n_jobs=4)
assert isinstance(p_explicit._backend, ThreadingBackend)
assert p_explicit.n_jobs == 4
# 2. Explicit backend="threading" preserves n_jobs=4 without resetting to 1
with parallel_config(n_jobs=4, backend="threading"):
p_threaded = Parallel()
assert isinstance(p_threaded._backend, ThreadingBackend)
assert p_threaded.n_jobs == 4
res = p_threaded(delayed(lambda x: x * 2)(i) for i in range(4))
assert res == [0, 2, 4, 6]
# 3. require="sharedmem" without explicit backend forces ThreadingBackend and resets implicit n_jobs to 1
with parallel_config(n_jobs=4, require="sharedmem"):
p_shared = Parallel()
assert isinstance(p_shared._backend, ThreadingBackend)
assert p_shared.n_jobs == 1
# 4. Contradictory prefer="processes" and require="sharedmem" raises ValueError
inconsistent_caught = False
try:
with parallel_config(prefer="processes", require="sharedmem"):
Parallel()
except ValueError as e:
assert "inconsistent settings" in str(e)
inconsistent_caught = True
assert inconsistent_caught
# 5. Direct constructor with incompatible backend and require="sharedmem" raises ValueError
direct_caught = False
try:
Parallel(backend="multiprocessing", require="sharedmem")
except ValueError as e:
assert "does not support shared memory" in str(e)
direct_caught = True
assert direct_caught
# 6. parallel_config with incompatible backend and require="sharedmem" downgrades to ThreadingBackend and n_jobs=1
with parallel_config(backend="multiprocessing", require="sharedmem", n_jobs=4):
p_downgraded = Parallel()
assert isinstance(p_downgraded._backend, ThreadingBackend)
assert p_downgraded.n_jobs == 1
# 7. Nested parallel_config overrides and cleanly restores outer configuration
with parallel_config(n_jobs=4, backend="threading"):
backend, n_jobs = jp.get_active_backend()
assert isinstance(backend, ThreadingBackend)
assert n_jobs == 4
with parallel_config(n_jobs=2):
p_inner = Parallel()
assert p_inner.n_jobs == 2
assert isinstance(p_inner._backend, ThreadingBackend)
p_outer = Parallel()
assert p_outer.n_jobs == 4
assert isinstance(p_outer._backend, ThreadingBackend)
# Outside parallel_config, LokyBackend is active again
backend_default, _ = jp.get_active_backend()
assert isinstance(backend_default, LokyBackend)
# 8. inner_max_num_threads without explicit backend raises ValueError at context entry
inner_caught = False
try:
with parallel_config(inner_max_num_threads=2):
pass
except ValueError as e:
assert "inner_max_num_threads and other constructor parameters" in str(e)
inner_caught = True
assert inner_caught
# 9. Unregistered backend name raises ValueError immediately at context entry
bad_backend_caught = False
try:
with parallel_config(backend="nonexistent"):
pass
except ValueError as e:
assert "Invalid backend: nonexistent" in str(e)
bad_backend_caught = True
assert bad_backend_caught
if __name__ == "__main__":
main()