Free-threaded Python (PEP 703)¶
CPython 3.13+ ships an optional GIL-free build (python3.13t,
python3.14t). On free-threaded Python, multi-threaded Python code can
truly execute in parallel — there’s no GIL serialising threads.
Why does this matter for merton?¶
Panel calibration over thousands of firms is embarrassingly parallel.
On standard GIL-enabled Python we use joblib with prefer="threads",
which works fine because our Numba kernels release the GIL inside @njit
blocks. But Python-side glue still pays a serialisation cost.
On free-threaded Python:
joblib’slokybackend transparently uses real threads.Our Numba kernels (
nogil=True) execute concurrently.concurrent.futures.ThreadPoolExecutorbecomes competitive with — and cheaper than — thelokyprocess backend for sub-second tasks.
Wheel matrix¶
We ship cp313t wheels for Linux, macOS Apple Silicon, and Windows.
Install:
uv python install 3.13t
uv venv --python 3.13t
uv pip install merton
python -c "import sys; print('GIL disabled:', not sys._is_gil_enabled())"
merton doctor reports the GIL status at a glance.
Caveats¶
Some C extensions (notably older
pyarrowbuilds) emit warnings the first time they’re imported on free-threaded Python. These warnings don’t break anything but can be noisy; we filter them in the test suite.The performance improvement depends on workload. Pure-Numba loops see little change (they already release the GIL); Python-heavy code paths (e.g. parallel
MertonModel.fitover thousands of firms) see the biggest wins.
CI¶
A dedicated free-threaded job in .github/workflows/test.yml runs the
unit + property + golden test suites under cp313t on every PR.