rsloop 0.1.5__tar.gz → 0.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. rsloop-0.1.7/.github/workflows/tests.yml +58 -0
  2. {rsloop-0.1.5 → rsloop-0.1.7}/Cargo.lock +60 -3
  3. {rsloop-0.1.5 → rsloop-0.1.7}/Cargo.toml +3 -1
  4. {rsloop-0.1.5 → rsloop-0.1.7}/PKG-INFO +62 -32
  5. {rsloop-0.1.5 → rsloop-0.1.7}/README.md +60 -30
  6. {rsloop-0.1.5 → rsloop-0.1.7}/benchmarks/README.md +3 -1
  7. {rsloop-0.1.5 → rsloop-0.1.7}/benchmarks/compare_event_loops.py +110 -7
  8. {rsloop-0.1.5 → rsloop-0.1.7}/demo/README.md +2 -0
  9. {rsloop-0.1.5 → rsloop-0.1.7}/justfile +3 -0
  10. {rsloop-0.1.5 → rsloop-0.1.7}/pyproject.toml +2 -2
  11. rsloop-0.1.7/python/rsloop/__init__.py +957 -0
  12. {rsloop-0.1.5 → rsloop-0.1.7}/scripts/build-wheels.sh +7 -74
  13. rsloop-0.1.7/scripts/python-versions.sh +74 -0
  14. rsloop-0.1.7/scripts/test-supported-pythons.sh +103 -0
  15. {rsloop-0.1.5 → rsloop-0.1.7}/src/fd_ops.rs +78 -18
  16. {rsloop-0.1.5 → rsloop-0.1.7}/src/lib.rs +2 -0
  17. {rsloop-0.1.5 → rsloop-0.1.7}/src/loop_core.rs +32 -0
  18. {rsloop-0.1.5 → rsloop-0.1.7}/src/process_transport.rs +202 -56
  19. {rsloop-0.1.5 → rsloop-0.1.7}/src/python_api.rs +174 -22
  20. {rsloop-0.1.5 → rsloop-0.1.7}/src/python_names.rs +10 -0
  21. {rsloop-0.1.5 → rsloop-0.1.7}/src/runtime.rs +222 -19
  22. {rsloop-0.1.5 → rsloop-0.1.7}/src/stream_transport.rs +505 -26
  23. {rsloop-0.1.5 → rsloop-0.1.7}/src/tls.rs +19 -0
  24. rsloop-0.1.7/src/windows_vibeio.rs +137 -0
  25. rsloop-0.1.7/tests/test_compat.py +217 -0
  26. rsloop-0.1.7/tests/test_run.py +366 -0
  27. {rsloop-0.1.5 → rsloop-0.1.7}/tests/test_tls.py +22 -6
  28. {rsloop-0.1.5 → rsloop-0.1.7}/uv.lock +1 -1
  29. rsloop-0.1.5/python/rsloop/__init__.py +0 -202
  30. rsloop-0.1.5/tests/test_run.py +0 -181
  31. {rsloop-0.1.5 → rsloop-0.1.7}/.github/workflows/wheels.yml +0 -0
  32. {rsloop-0.1.5 → rsloop-0.1.7}/.gitignore +0 -0
  33. {rsloop-0.1.5 → rsloop-0.1.7}/LICENSE +0 -0
  34. {rsloop-0.1.5 → rsloop-0.1.7}/build.rs +0 -0
  35. {rsloop-0.1.5 → rsloop-0.1.7}/demo/fastapi_service.py +0 -0
  36. {rsloop-0.1.5 → rsloop-0.1.7}/examples/01_basics.py +0 -0
  37. {rsloop-0.1.5 → rsloop-0.1.7}/examples/02_fd_and_sockets.py +0 -0
  38. {rsloop-0.1.5 → rsloop-0.1.7}/examples/03_streams.py +0 -0
  39. {rsloop-0.1.5 → rsloop-0.1.7}/examples/04_unix_and_accepted_socket.py +0 -0
  40. {rsloop-0.1.5 → rsloop-0.1.7}/examples/05_pipes_signals_subprocesses.py +0 -0
  41. {rsloop-0.1.5 → rsloop-0.1.7}/rsloop.png +0 -0
  42. {rsloop-0.1.5 → rsloop-0.1.7}/scripts/generate-test-tls-certs.sh +0 -0
  43. {rsloop-0.1.5 → rsloop-0.1.7}/src/async_event.rs +0 -0
  44. {rsloop-0.1.5 → rsloop-0.1.7}/src/blocking.rs +0 -0
  45. {rsloop-0.1.5 → rsloop-0.1.7}/src/callbacks.rs +0 -0
  46. {rsloop-0.1.5 → rsloop-0.1.7}/src/context.rs +0 -0
  47. {rsloop-0.1.5 → rsloop-0.1.7}/src/errors.rs +0 -0
  48. {rsloop-0.1.5 → rsloop-0.1.7}/src/fast_streams.rs +0 -0
  49. {rsloop-0.1.5 → rsloop-0.1.7}/src/profiler.rs +0 -0
  50. {rsloop-0.1.5 → rsloop-0.1.7}/tests/packages/aiohttp_test.py +0 -0
@@ -0,0 +1,58 @@
1
+ name: Tests
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ python_versions:
7
+ description: "Space-separated Python versions to test"
8
+ required: false
9
+ type: string
10
+ build_mode:
11
+ description: "Build profile to use with maturin develop"
12
+ required: true
13
+ default: release
14
+ type: choice
15
+ options:
16
+ - release
17
+ - debug
18
+
19
+ permissions:
20
+ contents: read
21
+
22
+ jobs:
23
+ test-supported-pythons:
24
+ name: supported-pythons
25
+ runs-on: ubuntu-latest
26
+
27
+ steps:
28
+ - name: Check out repository
29
+ uses: actions/checkout@v6
30
+ with:
31
+ persist-credentials: false
32
+
33
+ - name: Set up Python
34
+ uses: actions/setup-python@v6
35
+ with:
36
+ python-version: "3.13"
37
+
38
+ - name: Set up uv
39
+ uses: astral-sh/setup-uv@v6
40
+
41
+ - name: Set up Rust
42
+ uses: dtolnay/rust-toolchain@stable
43
+ with:
44
+ toolchain: 1.94.0
45
+
46
+ - name: Cache Cargo registry and target
47
+ uses: Swatinem/rust-cache@v2
48
+
49
+ - name: Run tests across supported Python versions
50
+ shell: bash
51
+ env:
52
+ RSLOOP_PYTHON_VERSIONS: ${{ inputs.python_versions }}
53
+ run: |
54
+ args=()
55
+ if [[ "${{ inputs.build_mode }}" == "debug" ]]; then
56
+ args+=(--debug)
57
+ fi
58
+ scripts/test-supported-pythons.sh "${args[@]}"
@@ -374,7 +374,7 @@ dependencies = [
374
374
  "crossbeam-queue",
375
375
  "flume",
376
376
  "futures-util",
377
- "io-uring",
377
+ "io-uring 0.7.11",
378
378
  "io_uring_buf_ring",
379
379
  "libc",
380
380
  "once_cell",
@@ -878,6 +878,16 @@ dependencies = [
878
878
  "str_stack",
879
879
  ]
880
880
 
881
+ [[package]]
882
+ name = "io-uring"
883
+ version = "0.6.4"
884
+ source = "registry+https://github.com/rust-lang/crates.io-index"
885
+ checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5"
886
+ dependencies = [
887
+ "bitflags 1.3.2",
888
+ "libc",
889
+ ]
890
+
881
891
  [[package]]
882
892
  name = "io-uring"
883
893
  version = "0.7.11"
@@ -896,7 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
896
906
  checksum = "1838759bb8c2f24cf05a35429d83145c4aa6af43f8ad38477295e12a7320a80e"
897
907
  dependencies = [
898
908
  "bytes",
899
- "io-uring",
909
+ "io-uring 0.7.11",
900
910
  "rustix",
901
911
  ]
902
912
 
@@ -1035,6 +1045,18 @@ dependencies = [
1035
1045
  "adler2",
1036
1046
  ]
1037
1047
 
1048
+ [[package]]
1049
+ name = "mio"
1050
+ version = "1.1.1"
1051
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1052
+ checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
1053
+ dependencies = [
1054
+ "libc",
1055
+ "log",
1056
+ "wasi",
1057
+ "windows-sys 0.61.2",
1058
+ ]
1059
+
1038
1060
  [[package]]
1039
1061
  name = "nix"
1040
1062
  version = "0.26.4"
@@ -1090,6 +1112,12 @@ version = "1.21.4"
1090
1112
  source = "registry+https://github.com/rust-lang/crates.io-index"
1091
1113
  checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
1092
1114
 
1115
+ [[package]]
1116
+ name = "oneshot"
1117
+ version = "0.2.1"
1118
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1119
+ checksum = "cfe21416a02c693fb9f980befcb230ecc70b0b3d1cc4abf88b9675c4c1457f0c"
1120
+
1093
1121
  [[package]]
1094
1122
  name = "openssl-probe"
1095
1123
  version = "0.2.1"
@@ -1346,7 +1374,7 @@ dependencies = [
1346
1374
 
1347
1375
  [[package]]
1348
1376
  name = "rsloop"
1349
- version = "0.1.5"
1377
+ version = "0.1.7"
1350
1378
  dependencies = [
1351
1379
  "async-std",
1352
1380
  "compio",
@@ -1362,6 +1390,8 @@ dependencies = [
1362
1390
  "rustls-pemfile",
1363
1391
  "signal-hook",
1364
1392
  "socket2",
1393
+ "tokio",
1394
+ "vibeio",
1365
1395
  "windows-sys 0.61.2",
1366
1396
  ]
1367
1397
 
@@ -1729,6 +1759,16 @@ dependencies = [
1729
1759
  "cfg-if",
1730
1760
  ]
1731
1761
 
1762
+ [[package]]
1763
+ name = "tokio"
1764
+ version = "1.50.0"
1765
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1766
+ checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
1767
+ dependencies = [
1768
+ "bytes",
1769
+ "pin-project-lite",
1770
+ ]
1771
+
1732
1772
  [[package]]
1733
1773
  name = "tracing"
1734
1774
  version = "0.1.44"
@@ -1824,6 +1864,23 @@ version = "0.9.5"
1824
1864
  source = "registry+https://github.com/rust-lang/crates.io-index"
1825
1865
  checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1826
1866
 
1867
+ [[package]]
1868
+ name = "vibeio"
1869
+ version = "0.2.5"
1870
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1871
+ checksum = "78dce705a708cacdd5822824342a8843abcceb9619e7079dc0e97b77dcc4ce1c"
1872
+ dependencies = [
1873
+ "crossbeam-queue",
1874
+ "futures-util",
1875
+ "io-uring 0.6.4",
1876
+ "libc",
1877
+ "mio",
1878
+ "oneshot",
1879
+ "slab",
1880
+ "tokio",
1881
+ "windows-sys 0.61.2",
1882
+ ]
1883
+
1827
1884
  [[package]]
1828
1885
  name = "wasi"
1829
1886
  version = "0.11.1+wasi-snapshot-preview1"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rsloop"
3
- version = "0.1.5"
3
+ version = "0.1.7"
4
4
  edition = "2021"
5
5
  description = "An event loop for asyncio written in Rust"
6
6
  license = "Apache-2.0"
@@ -33,6 +33,8 @@ signal-hook = "0.4"
33
33
  socket2 = "0.6"
34
34
 
35
35
  [target.'cfg(windows)'.dependencies]
36
+ tokio = { version = "1", default-features = false, features = ["io-util"] }
37
+ vibeio = { version = "0.2.5", default-features = false }
36
38
  windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_Pipes", "Win32_System_Threading"] }
37
39
 
38
40
  [build-dependencies]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rsloop
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -23,7 +23,7 @@ License-File: LICENSE
23
23
  Summary: An event loop for asyncio written in Rust
24
24
  Keywords: asyncio,event-loop,pyo3,python,rust
25
25
  Home-Page: https://github.com/RustedBytes/rsloop
26
- Author: RustedBytes
26
+ Author: Yehor Smoliakov <egorsmkv@gmail.com>
27
27
  Requires-Python: >=3.8
28
28
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
29
29
  Project-URL: Homepage, https://github.com/RustedBytes/rsloop
@@ -49,7 +49,7 @@ coroutines still run on the thread that calls `run_forever()` or
49
49
  The package exposes:
50
50
 
51
51
  - a native extension module at `rsloop._loop`
52
- - a Python wrapper in `python/rsloop/__init__.py`
52
+ - a Python wrapper in [`python/rsloop/__init__.py`](./python/rsloop/__init__.py)
53
53
  - `rsloop.Loop`, `rsloop.new_event_loop()`, and `rsloop.run(...)`
54
54
 
55
55
  Repository metadata currently targets Python `>=3.8`. The packaged project now
@@ -100,7 +100,7 @@ finally:
100
100
 
101
101
  Importing `rsloop` also patches `asyncio.set_event_loop()` so Python 3.8 can
102
102
  accept an `rsloop.Loop` instance, matching the behavior exercised by
103
- `tests/test_run.py`.
103
+ [`tests/test_run.py`](./tests/test_run.py).
104
104
 
105
105
  ## Verified Surface Area
106
106
 
@@ -177,8 +177,9 @@ The native fast-stream path is used only when:
177
177
 
178
178
  Otherwise `rsloop` falls back to the stdlib `asyncio.streams` helpers.
179
179
 
180
- The implementation lives in `src/fast_streams.rs` and is backed by the lower
181
- level transport code in `src/stream_transport.rs`.
180
+ The implementation lives in [`src/fast_streams.rs`](./src/fast_streams.rs) and
181
+ is backed by the lower level transport code in
182
+ [`src/stream_transport.rs`](./src/stream_transport.rs).
182
183
 
183
184
  ## Runtime Model
184
185
 
@@ -197,29 +198,15 @@ model, but has not finished eliminating every helper thread yet.
197
198
 
198
199
  These gaps are visible in the current implementation.
199
200
 
200
- - Stream transport flow control is partial:
201
- `pause_reading()` and `resume_reading()` work, but
202
- `get_write_buffer_size()` returns `0`,
203
- `get_write_buffer_limits()` returns `(0, 0)`, and
204
- `set_write_buffer_limits()` is a no-op.
205
- - Several compatibility parameters are currently accepted only to preserve API
206
- shape, not to provide full behavior:
207
- `happy_eyeballs_delay`, `interleave`, `all_errors`,
208
- `ssl_shutdown_timeout`, and
209
- `shutdown_default_executor(timeout=...)`.
210
201
  - TLS uses a `rustls` backend with a narrower compatibility surface than
211
202
  CPython's OpenSSL-backed `ssl` module. In particular, encrypted private keys
212
203
  are not supported yet, and the fast-stream monkeypatch still falls back to
213
204
  stdlib helpers whenever `ssl` is enabled. TLS transport internals also still
214
205
  use helper-thread paths instead of the newer runtime-thread `compio` socket
215
206
  path.
216
- - Subprocess support is intentionally incomplete:
217
- `preexec_fn` is unsupported, and text mode is rejected for
218
- `asyncio.create_subprocess_exec()` /
219
- `asyncio.create_subprocess_shell()` when using the stdlib subprocess stream
220
- protocol.
221
- - Low-level subprocess transport APIs do support text decoding when used with a
222
- custom subprocess protocol.
207
+ - Subprocess support still has one notable gap:
208
+ `preexec_fn` remains unsupported because running arbitrary Python between
209
+ `fork()` and `exec()` is unsafe in this runtime model.
223
210
  - Unix-specific APIs remain Unix-specific:
224
211
  `create_unix_server`, `create_unix_connection`,
225
212
  `add_signal_handler`, `remove_signal_handler`.
@@ -253,9 +240,9 @@ Build release wheels into `dist/wheels`:
253
240
  scripts/build-wheels.sh
254
241
  ```
255
242
 
256
- That script currently defaults to CPython `3.8 3.9 3.10 3.11 3.12 3.13 3.14`
257
- plus free-threaded `3.14t`, and uses `uv python install` / `uv python find` to
258
- locate interpreters.
243
+ [`scripts/build-wheels.sh`](./scripts/build-wheels.sh) currently defaults to
244
+ CPython `3.8 3.9 3.10 3.11 3.12 3.13 3.14` plus free-threaded `3.14t`, and
245
+ uses `uv python install` / `uv python find` to locate interpreters.
259
246
 
260
247
  ## Profiling
261
248
 
@@ -304,12 +291,19 @@ uv run python examples/04_unix_and_accepted_socket.py
304
291
  uv run python examples/05_pipes_signals_subprocesses.py
305
292
  ```
306
293
 
294
+ Example files:
295
+ [`examples/01_basics.py`](./examples/01_basics.py),
296
+ [`examples/02_fd_and_sockets.py`](./examples/02_fd_and_sockets.py),
297
+ [`examples/03_streams.py`](./examples/03_streams.py),
298
+ [`examples/04_unix_and_accepted_socket.py`](./examples/04_unix_and_accepted_socket.py),
299
+ [`examples/05_pipes_signals_subprocesses.py`](./examples/05_pipes_signals_subprocesses.py).
300
+
307
301
  The repository also includes:
308
302
 
309
- - `demo/fastapi_service.py` for running the same FastAPI app on stdlib
310
- `asyncio`, `uvloop`, or `rsloop`
311
- - `benchmarks/compare_event_loops.py` for callback, task, and TCP stream
312
- comparisons
303
+ - [`demo/fastapi_service.py`](./demo/fastapi_service.py) for running the same
304
+ FastAPI app on stdlib `asyncio`, `uvloop`, or `rsloop`
305
+ - [`benchmarks/compare_event_loops.py`](./benchmarks/compare_event_loops.py)
306
+ for callback, task, and TCP stream comparisons
313
307
 
314
308
  ## Benchmark
315
309
 
@@ -318,6 +312,42 @@ uv run --with maturin maturin develop --release
318
312
  uv run --with uvloop python benchmarks/compare_event_loops.py
319
313
  ```
320
314
 
321
- See `benchmarks/README.md` for workload details and extra flags, and
322
- `demo/README.md` for the FastAPI loop comparison demo.
315
+ An example output from that script on Linux with CPython 3.14.0:
316
+
317
+ ```
318
+ callbacks (200,000 ops)
319
+ loop median_s best_s ops_per_s vs_fastest
320
+ rsloop 0.041608 0.040585 4,806,807 1.00x
321
+ uvloop 0.087539 0.086690 2,284,707 2.10x
322
+ asyncio 0.229563 0.221348 871,222 5.52x
323
+
324
+ tasks (50,000 ops)
325
+ loop median_s best_s ops_per_s vs_fastest
326
+ uvloop 0.084425 0.083497 592,239 1.00x
327
+ rsloop 0.091845 0.090982 544,397 1.09x
328
+ asyncio 0.138782 0.137716 360,276 1.64x
329
+ tcp_streams mode: rsloop native fast streams
330
+
331
+ tcp_streams (5,000 ops)
332
+ loop median_s best_s ops_per_s vs_fastest
333
+ rsloop 0.119483 0.118451 41,847 1.00x
334
+ uvloop 0.119582 0.116446 41,812 1.00x
335
+ asyncio 0.138408 0.134438 36,125 1.16x
336
+ ```
337
+
338
+ See [`benchmarks/README.md`](./benchmarks/README.md) for workload details and
339
+ extra flags, and [`demo/README.md`](./demo/README.md) for the FastAPI loop
340
+ comparison demo.
341
+
342
+ ## Acknowledgements
343
+
344
+ `rsloop` builds on the Python `asyncio` model and is implemented with
345
+ [PyO3](https://pyo3.rs/) on the Rust side. The runtime and I/O work in the
346
+ current implementation rely in part on
347
+ [compio](https://github.com/compio-rs/compio).
348
+
349
+ ## License
350
+
351
+ This project is licensed under the Apache License, Version 2.0. See
352
+ [`LICENSE`](./LICENSE) for the full text.
323
353
 
@@ -17,7 +17,7 @@ coroutines still run on the thread that calls `run_forever()` or
17
17
  The package exposes:
18
18
 
19
19
  - a native extension module at `rsloop._loop`
20
- - a Python wrapper in `python/rsloop/__init__.py`
20
+ - a Python wrapper in [`python/rsloop/__init__.py`](./python/rsloop/__init__.py)
21
21
  - `rsloop.Loop`, `rsloop.new_event_loop()`, and `rsloop.run(...)`
22
22
 
23
23
  Repository metadata currently targets Python `>=3.8`. The packaged project now
@@ -68,7 +68,7 @@ finally:
68
68
 
69
69
  Importing `rsloop` also patches `asyncio.set_event_loop()` so Python 3.8 can
70
70
  accept an `rsloop.Loop` instance, matching the behavior exercised by
71
- `tests/test_run.py`.
71
+ [`tests/test_run.py`](./tests/test_run.py).
72
72
 
73
73
  ## Verified Surface Area
74
74
 
@@ -145,8 +145,9 @@ The native fast-stream path is used only when:
145
145
 
146
146
  Otherwise `rsloop` falls back to the stdlib `asyncio.streams` helpers.
147
147
 
148
- The implementation lives in `src/fast_streams.rs` and is backed by the lower
149
- level transport code in `src/stream_transport.rs`.
148
+ The implementation lives in [`src/fast_streams.rs`](./src/fast_streams.rs) and
149
+ is backed by the lower level transport code in
150
+ [`src/stream_transport.rs`](./src/stream_transport.rs).
150
151
 
151
152
  ## Runtime Model
152
153
 
@@ -165,29 +166,15 @@ model, but has not finished eliminating every helper thread yet.
165
166
 
166
167
  These gaps are visible in the current implementation.
167
168
 
168
- - Stream transport flow control is partial:
169
- `pause_reading()` and `resume_reading()` work, but
170
- `get_write_buffer_size()` returns `0`,
171
- `get_write_buffer_limits()` returns `(0, 0)`, and
172
- `set_write_buffer_limits()` is a no-op.
173
- - Several compatibility parameters are currently accepted only to preserve API
174
- shape, not to provide full behavior:
175
- `happy_eyeballs_delay`, `interleave`, `all_errors`,
176
- `ssl_shutdown_timeout`, and
177
- `shutdown_default_executor(timeout=...)`.
178
169
  - TLS uses a `rustls` backend with a narrower compatibility surface than
179
170
  CPython's OpenSSL-backed `ssl` module. In particular, encrypted private keys
180
171
  are not supported yet, and the fast-stream monkeypatch still falls back to
181
172
  stdlib helpers whenever `ssl` is enabled. TLS transport internals also still
182
173
  use helper-thread paths instead of the newer runtime-thread `compio` socket
183
174
  path.
184
- - Subprocess support is intentionally incomplete:
185
- `preexec_fn` is unsupported, and text mode is rejected for
186
- `asyncio.create_subprocess_exec()` /
187
- `asyncio.create_subprocess_shell()` when using the stdlib subprocess stream
188
- protocol.
189
- - Low-level subprocess transport APIs do support text decoding when used with a
190
- custom subprocess protocol.
175
+ - Subprocess support still has one notable gap:
176
+ `preexec_fn` remains unsupported because running arbitrary Python between
177
+ `fork()` and `exec()` is unsafe in this runtime model.
191
178
  - Unix-specific APIs remain Unix-specific:
192
179
  `create_unix_server`, `create_unix_connection`,
193
180
  `add_signal_handler`, `remove_signal_handler`.
@@ -221,9 +208,9 @@ Build release wheels into `dist/wheels`:
221
208
  scripts/build-wheels.sh
222
209
  ```
223
210
 
224
- That script currently defaults to CPython `3.8 3.9 3.10 3.11 3.12 3.13 3.14`
225
- plus free-threaded `3.14t`, and uses `uv python install` / `uv python find` to
226
- locate interpreters.
211
+ [`scripts/build-wheels.sh`](./scripts/build-wheels.sh) currently defaults to
212
+ CPython `3.8 3.9 3.10 3.11 3.12 3.13 3.14` plus free-threaded `3.14t`, and
213
+ uses `uv python install` / `uv python find` to locate interpreters.
227
214
 
228
215
  ## Profiling
229
216
 
@@ -272,12 +259,19 @@ uv run python examples/04_unix_and_accepted_socket.py
272
259
  uv run python examples/05_pipes_signals_subprocesses.py
273
260
  ```
274
261
 
262
+ Example files:
263
+ [`examples/01_basics.py`](./examples/01_basics.py),
264
+ [`examples/02_fd_and_sockets.py`](./examples/02_fd_and_sockets.py),
265
+ [`examples/03_streams.py`](./examples/03_streams.py),
266
+ [`examples/04_unix_and_accepted_socket.py`](./examples/04_unix_and_accepted_socket.py),
267
+ [`examples/05_pipes_signals_subprocesses.py`](./examples/05_pipes_signals_subprocesses.py).
268
+
275
269
  The repository also includes:
276
270
 
277
- - `demo/fastapi_service.py` for running the same FastAPI app on stdlib
278
- `asyncio`, `uvloop`, or `rsloop`
279
- - `benchmarks/compare_event_loops.py` for callback, task, and TCP stream
280
- comparisons
271
+ - [`demo/fastapi_service.py`](./demo/fastapi_service.py) for running the same
272
+ FastAPI app on stdlib `asyncio`, `uvloop`, or `rsloop`
273
+ - [`benchmarks/compare_event_loops.py`](./benchmarks/compare_event_loops.py)
274
+ for callback, task, and TCP stream comparisons
281
275
 
282
276
  ## Benchmark
283
277
 
@@ -286,5 +280,41 @@ uv run --with maturin maturin develop --release
286
280
  uv run --with uvloop python benchmarks/compare_event_loops.py
287
281
  ```
288
282
 
289
- See `benchmarks/README.md` for workload details and extra flags, and
290
- `demo/README.md` for the FastAPI loop comparison demo.
283
+ An example output from that script on Linux with CPython 3.14.0:
284
+
285
+ ```
286
+ callbacks (200,000 ops)
287
+ loop median_s best_s ops_per_s vs_fastest
288
+ rsloop 0.041608 0.040585 4,806,807 1.00x
289
+ uvloop 0.087539 0.086690 2,284,707 2.10x
290
+ asyncio 0.229563 0.221348 871,222 5.52x
291
+
292
+ tasks (50,000 ops)
293
+ loop median_s best_s ops_per_s vs_fastest
294
+ uvloop 0.084425 0.083497 592,239 1.00x
295
+ rsloop 0.091845 0.090982 544,397 1.09x
296
+ asyncio 0.138782 0.137716 360,276 1.64x
297
+ tcp_streams mode: rsloop native fast streams
298
+
299
+ tcp_streams (5,000 ops)
300
+ loop median_s best_s ops_per_s vs_fastest
301
+ rsloop 0.119483 0.118451 41,847 1.00x
302
+ uvloop 0.119582 0.116446 41,812 1.00x
303
+ asyncio 0.138408 0.134438 36,125 1.16x
304
+ ```
305
+
306
+ See [`benchmarks/README.md`](./benchmarks/README.md) for workload details and
307
+ extra flags, and [`demo/README.md`](./demo/README.md) for the FastAPI loop
308
+ comparison demo.
309
+
310
+ ## Acknowledgements
311
+
312
+ `rsloop` builds on the Python `asyncio` model and is implemented with
313
+ [PyO3](https://pyo3.rs/) on the Rust side. The runtime and I/O work in the
314
+ current implementation rely in part on
315
+ [compio](https://github.com/compio-rs/compio).
316
+
317
+ ## License
318
+
319
+ This project is licensed under the Apache License, Version 2.0. See
320
+ [`LICENSE`](./LICENSE) for the full text.
@@ -13,6 +13,8 @@ uv run --with maturin maturin develop --release
13
13
  uv run --with uvloop python benchmarks/compare_event_loops.py
14
14
  ```
15
15
 
16
+ Benchmark runner: [`benchmarks/compare_event_loops.py`](./compare_event_loops.py)
17
+
16
18
  The Rust prototype should be installed in release mode before benchmarking.
17
19
  Using the default debug build will heavily skew the comparison against
18
20
  `asyncio` and `uvloop`.
@@ -42,7 +44,7 @@ uv run --with uvloop python benchmarks/compare_event_loops.py \
42
44
  ```
43
45
 
44
46
  This writes one SVG per workload, such as
45
- `benchmarks/profiles/rsloop-callbacks.svg`, before the warmup and measured
47
+ [`benchmarks/profiles/rsloop-callbacks.svg`](./profiles/rsloop-callbacks.svg), before the warmup and measured
46
48
  passes.
47
49
 
48
50
  The runner executes each loop/workload in a fresh subprocess and reports: