A lock-free, high-concurrency task broker for Python, powered by Rust.
Project description
Pyroxide
A lock-free, high-concurrency background task broker for Python, powered by Rust.
Explore the Docs »
API Reference
·
See Examples
·
Report Bug
·
Request Feature
Pyroxide (pyro3) is a lightweight, ultra-high-performance background task broker designed to bridge Python and Rust. It allows CPU-bound or blocking workloads to bypass the Python Global Interpreter Lock (GIL) with minimal memory overhead and zero CPU-sleep polling.
Why Pyroxide?
- 🚀 Bypass the GIL (GIL-Free): Execute CPU-intensive compiled tasks on background OS threads without holding the Python GIL.
- ⚡ Microsecond Latency: Utilizes OS-level signaling (
Condvar) rather than CPU-burning thread polling, dispatching and completing tasks in under 25 microseconds. - 📦 Zero Infrastructure: Runs completely in-process. No Redis, RabbitMQ, or Celery worker daemons to configure or maintain.
- 💾 Zero-Copy Serialization: Pass large byte arrays, memoryviews, or columnar buffers across the C-ABI boundary without copy or
pickleoverhead. - 🛠️ On-the-Fly Native Compilers: Write code as Python strings and compile them to dynamic libraries on-the-fly (Rust, C, and Zig supported!).
- 🛡️ Isolated Worker Processes: Opt-in
isolated=Trueto run tasks in separate processes via cross-platform Named Pipes / Domain Sockets. Features bidirectional Zero-Copy Shared Memory (SHM) routing for payloads >= 1MB, and an auto-scaling Scale-to-Zero pool to reclaim memory. - 🔗 Task Groups & Workflows: Bundle multiple task handles into parallel groups (
group) to await or cancel them as a single logical unit.
Pyroxide vs. Alternatives
| Feature / Metric | Pyroxide | Threading (std) | Multiprocessing | Celery / RQ |
|---|---|---|---|---|
| GIL Bypass | ✅ Yes (WASM/dylib) | ❌ No | ✅ Yes | ✅ Yes |
| IPC / Serialization | ✅ None (Shared Memory) | ✅ None | ❌ High (Pickling) | ❌ High (Network/Redis) |
| Infrastructure | ✅ None (Embedded) | ✅ None | ⚠️ Low (Spawns processes) | ❌ High (Redis/RabbitMQ) |
| Best For | 🔥 High-perf in-process pipelines | I/O-bound Python | CPU-heavy Python | Distributed tasks |
For a detailed analysis, check out the Library Comparison Guide.
Installation
From PyPI
pip install pyro3
Build Locally
Ensure you have Rust, Python (3.8+), and maturin installed:
git clone https://github.com/emivvvvv/pyroxide.git
cd pyroxide
pip install maturin
maturin develop
Quick Start
1. Offload Python Callables
from pyroxide import task
@task
def calculate_square(x: int) -> int:
return x * x # Runs in background OS threads
# Submit and get a handle immediately
handle = calculate_square(12)
result = handle.result() # Blocks natively (0% CPU) until complete
print(result) # 144
# Pure Python tasks can fully bypass the GIL with `isolated=True`
@task(isolated=True)
def heavy_computation(x: int) -> int:
return sum(i * i for i in range(x))
2. Batch Submission & Task Groups
Submit tasks in bulk under a single lock acquisition to avoid thread contention, and manage them concurrently:
from pyroxide import task, group
@task
def calculate_square(x: int) -> int:
return x * x
payloads = [10, 20, 30, 40]
# 1. Batch submit payloads
handles = calculate_square.batch(payloads)
# 2. Bundle into a parallel TaskGroup
tg = group(handles)
print(tg.status) # "Running"
# 3. Retrieve results (consume=False preserves status metadata)
results = tg.result(consume=False)
print(results) # [100, 400, 900, 1600]
print(tg.status) # "Completed"
3. Sandboxed WebAssembly (GIL-Free)
Run computations GIL-free in a secure, virtual sandbox without compiling native code:
from pyroxide import register_wasm, wasm_task
# 1. Register WebAssembly bytecode
with open("rot13.wasm", "rb") as f:
register_wasm("rot13", f.read())
# 2. Decorate stub function
@wasm_task("rot13")
def rot13_cipher(payload: str) -> str:
pass
# 3. Execute GIL-free on the Rust worker pool!
print(rot13_cipher("hello").result()) # "uryyb"
4. Dynamic Shared Libraries (On-the-Fly Compilation)
Compile and load native code strings on-the-fly. Rust (compile_dylib), C (compile_c), and Zig (compile_zig) are supported:
from pyroxide import compile_dylib, dylib_task
RUST_SRC = """
#[no_mangle]
pub unsafe extern "C" fn pyroxide_plugin_run(ptr: *const u8, len: usize, out_len: *mut usize) -> *mut u8 {
let input = std::slice::from_raw_parts(ptr, len);
let s = std::str::from_utf8(input).unwrap_or("");
let result = s.to_uppercase().into_bytes();
*out_len = result.len();
let boxed = result.into_boxed_slice();
Box::into_raw(boxed) as *mut u8
}
#[no_mangle]
pub unsafe extern "C" fn pyroxide_plugin_free(ptr: *mut u8, len: usize) {
let _ = Box::from_raw(std::slice::from_raw_parts_mut(ptr, len));
}
"""
# Compile, register and load the Rust library on-the-fly!
compile_dylib("rust_upper", RUST_SRC)
@dylib_task("rust_upper")
def to_upper_rust(payload: str) -> str:
pass
print(to_upper_rust("hello from rust").result()) # "HELLO FROM RUST"
Dive Deeper (Documentation Book)
Detailed documentation, guides, and implementation examples are available in our Documentation Book:
- Asynchronous Event Loops: Non-blockingly await tasks using
await handle.result_async()in FastAPI/asyncio. Read Chapter. - Isolated Worker Processes: Sandbox tasks in separate OS processes for crash safety and GIL bypass. Read Chapter.
- Batch Submissions: Submit multiple tasks under a single lock acquisition to avoid thread contention. Read Chapter.
- Task Cancellation: Gracefully abort long-running background tasks mid-flight. Read Chapter.
- Traceback Preservation: Capture stack traces on background worker threads and propagate them to the main thread. Read Chapter.
- Memory Footprint & GC: Learn how Slab memory is reclaimed automatically using GC destructors. Read Chapter.
Performance At-a-Glance
We benchmarked Pyroxide against CPython's standard concurrency pools using identical compute payloads (recursive Fibonacci 20 workload) on Apple M1 Pro (8 cores, 16GB RAM):
| Metric (500 Tasks) | Pyroxide @dylib_task |
Pyroxide @task(isolated=True) |
Pyroxide @task |
Threading (std) | Multiprocessing |
|---|---|---|---|---|---|
| Execution Time | 0.0200 s |
0.0769 s |
0.3878 s |
0.3742 s |
2.0786 s |
| GIL Bypass | ✅ Yes (GIL-Free) | ✅ Yes | ❌ No | ❌ No | ✅ Yes |
| IPC / Serialization | ✅ None (Shared Memory) | ✅ Zero-Copy SHM | ✅ None | ✅ None | ❌ High (pickle cost) |
| Relative Speedup | 🔥 100x faster | 🔥 27x faster | 5x faster | 5x faster | Baseline (1x) |
- Bypassing the Multiprocessing Bottleneck: While Python's
ProcessPoolExecutortakes over 2 seconds due to slow process spawning and heavypickleIPC serialization, Pyroxide's@dylib_taskruns native compiled plugins in just 20 milliseconds—offering a 100x speedup with zero-copy shared memory.
Real-World Odoo Enterprise Arrow Ledger Audit Benchmark
To test performance under realistic enterprise data movement workloads, we ran a simulated Odoo Ledger Audit benchmark processing a 9.62 MB Apache Arrow serialized transaction recordset (200,000 journal items) across 10 concurrent requests comparing different concurrency strategies:
- CPython ThreadPoolExecutor (GIL-Locked):
0.3221 s - Pyroxide Threaded
@task(GIL-Locked):0.3298 s(matches Python's native scheduling overhead perfectly) - ProcessPoolExecutor (Python, Pickled Pipes):
0.2758 s - Pyroxide SHM Isolated
@task(Zero-Copy SHM):0.3272 s - Pyroxide
@dylib_task(C-compiled, GIL-Free):0.0091 s(bypasses GIL entirely)
Key Takeaway: By offloading the audit logic to a dynamically compiled C/Rust plugin running on Pyroxide's background thread pool, we achieve a 35.3x speedup over CPython's standard ThreadPoolExecutor by completely bypassing the GIL.
To run the Odoo simulation suite locally:
python examples/odoo_poc/odoo_complex_simulation.py
To run the comparative and basic benchmark suites locally:
# 1. Run detailed comparative benchmarks against CPython concurrency pools
python examples/benchmarks/benchmark_vs_alternatives.py
# 2. Run basic scheduling latency and asyncio benchmarks
python examples/benchmarks/benchmark.py
Contributing
Contributions are welcome! If you'd like to improve Pyroxide or add support for additional features, feel free to open an issue or submit a pull request on GitHub.
License
Pyroxide is licensed under any of:
- MIT License (LICENSE-MIT)
- Apache License, Version 2.0 (LICENSE-APACHE)
- Coffeeware License (LICENSE-COFFEE)
at your option.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyro3-0.5.1.tar.gz.
File metadata
- Download URL: pyro3-0.5.1.tar.gz
- Upload date:
- Size: 86.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc4a219fb76afb3cf4c28b0175ea7624d5d15f85bbbb2db35526dafc679d95f1
|
|
| MD5 |
2da380783c1010fdfeaf6f1f06307c32
|
|
| BLAKE2b-256 |
85e67f6efab587953a51a02bd6c92825491fd9efb33fbf905f4705f6e5722912
|
File details
Details for the file pyro3-0.5.1-cp38-abi3-win_amd64.whl.
File metadata
- Download URL: pyro3-0.5.1-cp38-abi3-win_amd64.whl
- Upload date:
- Size: 3.3 MB
- Tags: CPython 3.8+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0e683bf0f9906e56b31eebfe5a09149f7c08b503bf1c31598e605fa2e07e381
|
|
| MD5 |
94e81cbde9f17588137c984309178766
|
|
| BLAKE2b-256 |
59580da0ab407a688e81182af7d2fd7094e58a7f7d93df2717921eb629617571
|
File details
Details for the file pyro3-0.5.1-cp38-abi3-manylinux_2_39_x86_64.whl.
File metadata
- Download URL: pyro3-0.5.1-cp38-abi3-manylinux_2_39_x86_64.whl
- Upload date:
- Size: 4.2 MB
- Tags: CPython 3.8+, manylinux: glibc 2.39+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
594e09b2f5fb51280b4a4d8c41de3cd532e6190b9caf5f4306ba75db17a81a8f
|
|
| MD5 |
217bd39ae6e049da9ff34995885de1e5
|
|
| BLAKE2b-256 |
b19d78a5a18e11a3992a9d8669cfcd8cb47aa92530564741627ef20c664d7ddb
|
File details
Details for the file pyro3-0.5.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pyro3-0.5.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.0 MB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd1a6b25e6fe47ea8f741a93db0068644629b0f7adda6955a213c8841eb9851f
|
|
| MD5 |
38b364bf429169f68edbcd679fbe1c35
|
|
| BLAKE2b-256 |
18cc16849ec83c2dcf9f14903b8a5326b3226c291807eb8ead2b9d7768e8ab0a
|
File details
Details for the file pyro3-0.5.1-cp38-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: pyro3-0.5.1-cp38-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.7 MB
- Tags: CPython 3.8+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45b9e66758111aef7e556e4cc4a752a00e574b8790884d58e75cd0d6e5e99f0d
|
|
| MD5 |
a4db06d7faf31ac58bf4f443a5f2cfdc
|
|
| BLAKE2b-256 |
771b8eae58026480a471810ea4b5f7fea00f30b34a289f589780b2ff3f9ce1ac
|
File details
Details for the file pyro3-0.5.1-cp38-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: pyro3-0.5.1-cp38-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 3.8 MB
- Tags: CPython 3.8+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79b19f7b49a3e96a0dd42ed60ead53b31d897312c127cf6a9317ee8b9bf55274
|
|
| MD5 |
1db8d779eaedaa0318ce7f8bc46ce5f1
|
|
| BLAKE2b-256 |
f177dae6c93008bd56233d4fced4c47273cf1b7bdbe2962b48f949c11803cd03
|