Skip to content

GIL-free Runtime

Experimental feature

The GIL-free runtime is experimental. The default multiprocessing runtime remains the stable runtime for normal dbworkload runs.

Python free-threaded builds can run Python bytecode without the Global Interpreter Lock (GIL). In dbworkload, this makes it possible to experiment with a simpler thread-based runtime:

one Python process
many worker threads
shared in-process stats

This avoids the process supervisor and multiprocessing queue machinery used by the default runtime.

Usage

Use the experimental runtime with:

dbworkload run \
    --runtime gil-free \
    -w bank.py \
    --uri 'postgres://user:password@localhost:26257/bank?sslmode=disable' \
    --concurrency 8 \
    --duration 60

The runtime is useful when testing Python free-threaded builds such as python3.14t.

HTTP Control Endpoint

The GIL-free runtime starts a small HTTP control endpoint by default on port 26160. It listens on IPv4 0.0.0.0 and IPv6 [::].

Use adjust_count to add or remove workers while the run is active:

curl "http://localhost:26160/?adjust_count=5"
curl "http://localhost:26160/?adjust_count=-2"

The endpoint adjusts the target worker count. Connections are added or removed through the same internal worker machinery used by schedule and max-rate control, so changes are cooperative rather than forcibly interrupting in-flight work.

Use --control-port to choose a different port:

dbworkload run --runtime gil-free --control-port 8282 ...

Current Limitations

The GIL-free runtime supports fixed-concurrency runs, --max-rate, and schedule rows that set connection count, max rate, ramp time, and duration. It also supports live connection changes through the HTTP control endpoint.

This feature is not implemented yet:

  • live connection changes through dbworkload.pipe

If you need those features, use the default runtime:

dbworkload run --runtime multiprocessing ...

Schedule Support

The GIL-free runtime supports schedule rows like:

connections,max_rate,ramp,duration
2,,0,1
8,,2,5
1,,0,1

It also supports rows that use max_rate:

connections,max_rate,ramp,duration
,3000,0,5
4,3000,1,5

When max_rate is set and connections is empty or zero, dbworkload starts with one worker, measures __cycle__ throughput, and extrapolates how many workers are needed. If the workload overshoots the target, each worker adds a small per-cycle pause to float around the requested rate.

Checking the GIL

When testing this runtime, confirm that the Python interpreter is actually a free-threaded build:

python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))"

Expected output:

1

Some native extensions may cause Python to re-enable the GIL at runtime. To make that visible during testing, run with:

PYTHON_GIL=0 dbworkload run --runtime gil-free ...

If the GIL is re-enabled, dbworkload should refuse to continue once the runtime guard detects it.