Rsloop
An event loop for asyncio written in Rust
Install / Use
/learn @RustedBytes/RsloopREADME
An event loop for asyncio written in Rust
rsloop is a PyO3-based asyncio event loop implemented in Rust.
Each rsloop.Loop owns a dedicated Rust runtime thread for loop coordination
and I/O work. On Linux, low-level fd watchers plus plain TCP / Unix socket
readiness, socket reads, and non-TLS server accepts are driven from that thread
through compio with io_uring support enabled. Python callbacks, tasks, and
coroutines still run on the thread that calls run_forever() or
run_until_complete() (usually the main Python thread).
The package exposes:
- a native extension module at
rsloop._loop - a Python wrapper in
python/rsloop/__init__.py rsloop.Loop,rsloop.new_event_loop(), andrsloop.run(...)
Repository metadata currently targets Python >=3.8. The packaged project now
supports the core event-loop surface on Linux, macOS, and Windows, including
Windows pipe transports and subprocess workflows.
Documentation
Project documentation now lives in docs/.
If you are new to the repository, start with:
To browse the docs locally with MkDocs:
uvx --from mkdocs mkdocs serve
Install
From PyPI:
pip install rsloop
With uv:
uv add rsloop
Usage
Simple entry point:
import rsloop
async def main():
...
rsloop.run(main())
Manual loop creation also works:
import asyncio
import rsloop
loop = rsloop.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(...)
finally:
asyncio.set_event_loop(None)
loop.close()
Importing rsloop also patches asyncio.set_event_loop() so Python 3.8 can
accept an rsloop.Loop instance, matching the behavior exercised by
tests/test_run.py.
Custom Async Rust Extensions
rsloop now exposes a small Rust interop API for downstream PyO3 extensions.
That lets you write your own async Rust code, return it to Python as an
awaitable, and run it under the active rsloop event loop.
The public entry point is rsloop::rust_async:
get_current_locals(...)future_into_py(...)future_into_py_with_locals(...)local_future_into_py(...)local_future_into_py_with_locals(...)- re-exports of
TaskLocalsandinto_future_with_locals(...)
See examples/rust/README.md for a complete
extension example built with maturin.
Verified Surface Area
The current codebase implements these user-facing areas.
Loop lifecycle and scheduling:
run_forever,run_until_complete,stop,closetime,is_running,is_closedget_debug,set_debugcall_soon,call_soon_threadsafe,call_later,call_at- returned
HandleandTimerHandleobjects withcancel()/cancelled()
Tasks, futures, and execution helpers:
create_future,create_taskset_task_factory,get_task_factoryset_exception_handler,get_exception_handler,call_exception_handler,default_exception_handlerset_default_executor,run_in_executorshutdown_asyncgens,shutdown_default_executor- callback execution under captured
contextvars.Context asyncio.get_running_loop()support while running onrslooprsloop.run(...)helper, withasyncio.run(..., loop_factory=...)integration on Python 3.12+
I/O and networking:
add_reader,remove_reader,add_writer,remove_writersock_recv,sock_recv_into,sock_sendall,sock_accept,sock_connectgetaddrinfo,getnameinfocreate_server,create_connectioncreate_unix_server,create_unix_connectionconnect_accepted_socket- returned
Serverobjects withclose(),is_serving(),get_loop(), andsockets() - returned
StreamTransportobjects withwrite(),writelines(),close(),abort(),is_closing(),write_eof(),can_write_eof(),get_extra_info(),get_protocol(),set_protocol(),pause_reading(),resume_reading(),is_reading()
Pipes, subprocesses, and signals:
connect_read_pipe,connect_write_pipesubprocess_exec,subprocess_shell- returned
ProcessTransportandProcessPipeTransportobjects - higher-level compatibility with
asyncio.create_subprocess_exec()andasyncio.create_subprocess_shell() - Unix subprocess options including
cwd,env,executable,pass_fds,start_new_session,process_group,user,group,extra_groups,umask, andrestore_signals add_signal_handler,remove_signal_handler
Profiling:
profile(...),profiler_running(),start_profiler(),stop_profiler()
Fast Streams
Importing rsloop patches asyncio.open_connection() and
asyncio.start_server() by default.
That import-time behavior is controlled by RSLOOP_USE_FAST_STREAMS and can be
disabled with:
export RSLOOP_USE_FAST_STREAMS=0
The native fast-stream path is used only when:
- the running loop is an
rsloop.Loop sslis unset orNone
Otherwise rsloop falls back to the stdlib asyncio.streams helpers.
The implementation lives in src/fast_streams.rs and
is backed by the lower level transport code in
src/stream_transport.rs.
Runtime Model
Today the runtime is hybrid rather than fully single-threaded:
- the loop coordination thread is always the central scheduler
- on Linux,
add_reader/add_writer, plain socket reads, and non-TLS socket accept loops use thecompioruntime on that thread - some transport paths still fall back to helper threads, especially TLS I/O, TLS server accept, and parts of the legacy transport write path
That means the codebase has started the move toward a single-runtime-thread I/O model, but has not finished eliminating every helper thread yet.
Current Limitations
These gaps are visible in the current implementation.
- TLS uses a
rustlsbackend with a narrower compatibility surface than CPython's OpenSSL-backedsslmodule. In particular, encrypted private keys are not supported yet, and the fast-stream monkeypatch still falls back to stdlib helpers wheneversslis enabled. TLS transport internals also still use helper-thread paths instead of the newer runtime-threadcompiosocket path. - Subprocess support still has one notable gap:
preexec_fnremains unsupported because running arbitrary Python betweenfork()andexec()is unsafe in this runtime model. - Unix-specific APIs remain Unix-specific:
create_unix_server,create_unix_connection,add_signal_handler,remove_signal_handler. - Platform-specific limitations still apply:
Unix socket APIs and Unix signal handlers remain Unix-only, and several
subprocess options such as
pass_fds,user,group, andumaskare still specific to Unix process spawning. - The transport runtime model is still in transition: plain socket reads and non-TLS accepts now run on the loop runtime thread on Linux, but writes and TLS-heavy paths are not fully collapsed onto that same single-threaded I/O path yet.
Build
Quick check:
cargo check
Release build and editable install:
cargo build --release
uv run --with maturin maturin develop --release
Build release wheels into dist/wheels:
scripts/build-wheels.sh
scripts/build-wheels.sh currently defaults to
CPython 3.8 3.9 3.10 3.11 3.12 3.13 3.14 plus free-threaded 3.14t, and
uses uv python install / uv python find to locate interpreters.
Profiling
Profiling is behind the Cargo feature profiler and is disabled by default.
Build or install with that feature first:
cargo build --release --features profiler
uv run --with maturin maturin develop --release --features profiler
Then wrap the code you want to inspect:
import rsloop
with rsloop.profile():
rsloop.run(main())
Or manage the session manually:
import rsloop
rsloop.start_profiler()
try:
rsloop.run(main())
finally:
rsloop.stop_profiler()
This starts a Tracy client inside the process. Build a release binary, open
tracy-profiler.exe, then connect to the running process while the profiled
code is executing.
The current Tracy feature set is aimed at local Windows profiling:
enable, only-localhost, sampling, and flush-on-exit. The last one helps
short-lived runs flush data before exit.
If the extension was built without --features profiler, profile() and
start_profiler() raise a runtime error.
Examples
Run the repository examples from the project root:
uv run python examples/01_basics.py
uv run python examples/02_fd_and_sockets.py
uv run python examples/03_streams.py
uv run python examples/04_unix_and_accepted_socket.py
uv run python examples/05_pipes_signals_subprocesses.py
Example files:
examples/01_basics.py,
examples/02_fd_and_sockets.py,
examples/03_streams.py,
examples/04_unix_and_accepted_socket.py,
examples/05_pipes_signals_subprocesses.py.
The repository also includes
Related Skills
node-connect
347.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
107.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
