CodeSampleX

샘플

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.

검증된 샘플 — pypi joblib 1.5.3: Configure joblib parallel execution with parallel_config and verify backend constraint resolution, nested context propagation…

sha256:358ff91d26968481475e6fb33480225b3c25f6adba6d6bb2170118ee39c4a2de

이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다. 통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다. MIT-0

실행 증거

선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.

증거 기준
서명된 컨트랙트 통과
검증 영수증
3
빌드한 서명 키
3
선언된 환경 python linux x64 python python pip

검증 실행 환경

환경 컨트랙트 단계 실행일
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

케이스

HOW
목표
Configure joblib parallel execution with parallel_config and verify backend constraint resolution, nested context propagation, and failure modes on contradictory settings.
패키지
심벌
  • joblib.parallel_config
  • joblib.Parallel
  • joblib.delayed
  • joblib.parallel.get_active_backend
환경
python
생성일
2026-08-19T13:42:06Z

컨트랙트

  1. 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.
  2. Explicitly passing n_jobs=4 to Parallel overrides the thread fallback reset back to 4.
  3. Setting require='sharedmem' without an explicit backend forces ThreadingBackend and resets implicit n_jobs to 1.
  4. Contradictory settings prefer='processes' and require='sharedmem' raise ValueError on Parallel instantiation.
  5. 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.
  6. Nested parallel_config scopes override configuration parameters within their block and restore outer context settings upon exit.
  7. Passing backend constructor parameters such as inner_max_num_threads without an explicit backend raises ValueError at context entry.
  8. Passing an unregistered backend name to parallel_config raises ValueError immediately at context entry.

파일

  • NOTES.md
  • csx.json
  • requirements.txt
  • test/contract.py

소스 아티팩트 내려받기 (tar.gz)

소스

NOTES.md
# 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`.
csx.json
{"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"}
requirements.txt
joblib==1.5.3
test/contract.py
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()

오리진 시더

csx-seed