A Python implementation of a liburing-based proactor event loop for asyncio, designed to follow Python standard library conventions. The implementation is written primarily in pure Python, using CFFI only for wrapping the liburing interface.
- Implements a Proactor pattern similar to Windows' IOCP (reference implementation)
- Follows Python's standard asyncio implementation patterns
⚠️ Note: This is currently experimental and not yet stable
- Provide a primarily Python (with CFFI, maybe C extention in future) implementation of a liburing-based event loop
- Maintain full compatibility with standard asyncio APIs
- Follow Python standard library implementation patterns
-
Linux 5.19+ kernel
-
Python 3.12+
-
liburing development libraries
sudo apt install liburing-dev
- Using uv:
uv add uringloop
- Using pip:
pip install uringloop
Set the event loop policy with asyncio.set_event_loop_policy(IouringProactorEventLoopPolicy()) to use the io_uring-based event loop.
import asyncio
from uringloop import IouringProactorEventLoopPolicy
asyncio.set_event_loop_policy(IouringProactorEventLoopPolicy())
async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
addr = writer.get_extra_info('peername')
print(f"Connection from {addr}")
while True:
data = await reader.read(1024)
if not data:
break
print(f"Received: {data.decode()}")
writer.write(data)
await writer.drain()
print(f"Connection with {addr} closed")
writer.close()
async def start_server():
server = await asyncio.start_server(
handle_client, '127.0.0.1', 8888)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
await server.serve_forever()
async def tcp_client(message: str):
reader, writer = await asyncio.open_connection(
'127.0.0.1', 8888)
print(f'Send: {message!r}')
writer.write(message.encode())
await writer.drain()
data = await reader.read(100)
print(f'Received: {data.decode()!r}')
print('Closing connection')
writer.close()
await writer.wait_closed()
async def main():
# Start the server in the background
server_task = asyncio.create_task(start_server())
# Give the server a moment to start
await asyncio.sleep(1)
# Run the client
await tcp_client('Hello, World!')
# Cancel the server task (otherwise it runs forever)
server_task.cancel()
try:
await server_task
except asyncio.CancelledError:
pass
if __name__ == "__main__":
asyncio.run(main())
the result would looks like
Serving on ('127.0.0.1', 8888)
Send: 'Hello, World!'
Connection from ('0.0.0.0', 0)
Received: Hello, World!
Received: 'Hello, World!'
Closing connection
Connection with ('0.0.0.0', 0) closed
Contributions are welcome! Please open issues or pull requests for any bugs or feature requests.
This project is licensed under the terms of the MIT license.
- workflow
- use registered fd and buffer
- add signal handling
- refactor e2e test
- benchmark
- figure out a way to do unit/integration test