High-performance asyncio event loop for Python using io_uring - 36% faster than asyncio
Project description
uringcore
A high-performance asyncio event loop for Linux using io_uring.
Introduction
uringcore provides a drop-in replacement for Python's asyncio event loop, built on the io_uring interface available in Linux kernel 5.11+. The project targets use cases where low-latency I/O and high throughput are critical requirements.
The implementation leverages a completion-driven architecture rather than the traditional readiness-based model used by epoll. This design eliminates syscalls from the hot path, resulting in measurable performance improvements for network-intensive applications.
Use Cases
- High-frequency trading systems requiring sub-millisecond latency
- Real-time data pipelines processing millions of messages per second
- API gateways handling high concurrent connection counts
- WebSocket servers with persistent connections
- Database connection pools with intensive query workloads
Requirements
- Linux kernel 5.11+ (for
IORING_OP_PROVIDE_BUFFERS) - Python 3.10+
- Rust 1.70+
Optional:
- SQPOLL mode requires
CAP_SYS_ADMINor kernel 5.12+ with unprivileged SQPOLL
Installation
From PyPI (when published)
pip install uringcore
From Source
git clone https://github.com/ankitkpandey1/uringcore.git
cd uringcore
# Create virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install build dependencies
pip install maturin
# Build and install
maturin develop
Quick Start
Replace the default asyncio event loop with uringcore:
import asyncio
import uringcore
# Set the event loop policy
asyncio.set_event_loop_policy(uringcore.EventLoopPolicy())
async def main():
# Standard asyncio code works unchanged
await asyncio.sleep(1)
print("Hello from uringcore!")
asyncio.run(main())
With FastAPI
import asyncio
import uringcore
from fastapi import FastAPI
asyncio.set_event_loop_policy(uringcore.EventLoopPolicy())
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Powered by uringcore"}
With Starlette
import asyncio
import uringcore
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
asyncio.set_event_loop_policy(uringcore.EventLoopPolicy())
async def homepage(request):
return JSONResponse({"hello": "world"})
app = Starlette(routes=[Route("/", homepage)])
Performance
Verified benchmark results against standard asyncio and uvloop:
| Metric | uringcore | asyncio | uvloop |
|---|---|---|---|
| Throughput | 15,394 req/s | 11,317 req/s | 11,721 req/s |
| p50 Latency | 58 µs | 83 µs | 78 µs |
| p99 Latency | 121 µs | 181 µs | 182 µs |
| vs asyncio | +36% | baseline | +4% |
See BENCHMARK.md for methodology and detailed analysis.
Features
- Pure io_uring - No fallback to epoll for core I/O
- TCP Support -
create_server,create_connection,start_server - UDP Support -
create_datagram_endpoint - Unix Sockets -
create_unix_server,create_unix_connection - Subprocess -
subprocess_exec,subprocess_shell - Signal Handlers -
add_signal_handler,remove_signal_handler - Executor Integration -
run_in_executorfor blocking calls - Reader/Writer Callbacks -
add_reader,add_writerfor 3rd-party compatibility - Connection Timeouts -
IORING_OP_LINK_TIMEOUTsupport
Project Structure
uringcore/
├── src/ # Rust core implementation
│ ├── lib.rs # PyO3 module entry point
│ ├── buffer.rs # Zero-copy buffer pool
│ ├── ring.rs # io_uring wrapper with LINK_TIMEOUT
│ ├── state.rs # FD state machine
│ └── error.rs # Error types
├── python/ # Python layer
│ └── uringcore/
│ ├── __init__.py
│ ├── loop.py # UringEventLoop
│ ├── policy.py # EventLoopPolicy
│ ├── transport.py # Socket transport
│ ├── datagram.py # UDP transport
│ ├── subprocess.py # Subprocess transport
│ └── ssl_transport.py # SSL/TLS wrapper
├── tests/ # Test suites
│ ├── test_basic.py # Unit tests
│ ├── test_stress.py # Concurrent stress tests
│ ├── test_asyncio_compat.py # asyncio API tests
│ └── e2e/
│ ├── starlette/
│ └── fastapi/
└── benchmarks/ # Performance benchmarks
Documentation
- Architecture - Design decisions and system overview
- Benchmarks - Performance measurements and analysis
Development
Running Tests
# Rust tests
cargo test
# Python tests
source .venv/bin/activate
pytest tests/ -v
# All tests including e2e
pytest tests/ tests/e2e/ -v
Code Quality
# Rust formatting and linting
cargo fmt
cargo clippy --all-targets -- -D warnings
# Python linting (if ruff/black installed)
ruff check .
License
SPDX-License-Identifier: Apache-2.0
Copyright 2024 Ankit Kumar Pandey <ankitkpandey1@gmail.com>
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Author
Ankit Kumar Pandey - ankitkpandey1@gmail.com
Acknowledgments
- The io_uring subsystem maintainers, particularly Jens Axboe
- The PyO3 project for Rust-Python bindings
- The uvloop project for demonstrating high-performance event loop implementation
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 Distribution
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 uringcore-0.9.0.tar.gz.
File metadata
- Download URL: uringcore-0.9.0.tar.gz
- Upload date:
- Size: 59.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38b8dba0a1c83d0c58133d087a18edbae45ca7b91a721908db8b5f24716a6c65
|
|
| MD5 |
770a988071baae027219f487c9596820
|
|
| BLAKE2b-256 |
8e2b8af9f47e591362a953e370cd9469af46e7bb7cf08bfa2aac299daaab13b0
|
File details
Details for the file uringcore-0.9.0-cp313-cp313-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: uringcore-0.9.0-cp313-cp313-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 263.1 kB
- Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.10.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8656ae81eaef24d23789999ad04c2f362a7902c01aee459c35e6da35124ef086
|
|
| MD5 |
018730d3194727e72486ffa155c8af96
|
|
| BLAKE2b-256 |
955f0322b2f888d78562e2c8678390060428487d7f59010f907f9a9e2e9bc0c4
|