rsloop 0.1.48__tar.gz → 0.1.50__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.
- {rsloop-0.1.48 → rsloop-0.1.50}/.github/workflows/tests.yml +1 -48
- rsloop-0.1.50/.github/workflows/vibeio-native.yml +109 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/Cargo.lock +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/Cargo.toml +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/PKG-INFO +91 -52
- {rsloop-0.1.48 → rsloop-0.1.50}/README.md +90 -51
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/README.md +36 -11
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/compare_event_loops.py +9 -3
- rsloop-0.1.50/benches/full-benchmark-6cc3444.md +115 -0
- rsloop-0.1.50/benches/full-benchmark-9011c9f.md +69 -0
- rsloop-0.1.50/benches/optimization-results.md +163 -0
- rsloop-0.1.50/benches/optimization_matrix_ab.py +112 -0
- rsloop-0.1.50/benches/optimization_probes.py +297 -0
- rsloop-0.1.50/benches/reactor-performance.md +176 -0
- rsloop-0.1.50/benches/results/full-6cc3444-idle.json +1275 -0
- rsloop-0.1.50/benches/results/full-6cc3444-matrix.json +6321 -0
- rsloop-0.1.50/benches/results/full-6cc3444-micro.json +801 -0
- rsloop-0.1.50/benches/results/full-9011c9f-idle.json +1225 -0
- rsloop-0.1.50/benches/results/full-9011c9f-matrix.json +6271 -0
- rsloop-0.1.50/benches/results/full-9011c9f-micro.json +559 -0
- rsloop-0.1.50/benches/results/optimization-matrix-2026-09-07.json +2139 -0
- rsloop-0.1.50/benches/results/optimization-probes-2026-09-07.json +377 -0
- rsloop-0.1.50/benches/results/reactor-performance-2026-09-07.json +4133 -0
- rsloop-0.1.50/benches/results/systems-performance-2026-09-07.json +9662 -0
- rsloop-0.1.50/benches/systems-performance.md +206 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/workload_matrix.py +2 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/development.md +28 -6
- {rsloop-0.1.48 → rsloop-0.1.50}/justfile +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/pyproject.toml +17 -2
- {rsloop-0.1.48 → rsloop-0.1.50}/qualirs.toml +11 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/run_python_tests.py +6 -5
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/test-supported-pythons.sh +3 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/executor.rs +79 -4
- rsloop-0.1.50/src/bindings/loop_api/fast_callbacks.rs +142 -0
- rsloop-0.1.50/src/bindings/loop_api/sock_ops.rs +113 -0
- rsloop-0.1.50/src/bindings/loop_api/socket_operation.rs +356 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api.rs +3 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/mod.rs +1 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/engine/callbacks.rs +20 -3
- {rsloop-0.1.48 → rsloop-0.1.50}/src/engine/commands.rs +0 -8
- {rsloop-0.1.48 → rsloop-0.1.50}/src/engine/dispatcher.rs +3 -88
- {rsloop-0.1.48 → rsloop-0.1.50}/src/engine/loop_core.rs +163 -16
- {rsloop-0.1.48 → rsloop-0.1.50}/src/engine/mod.rs +2 -0
- {rsloop-0.1.48/src/engine/dispatcher → rsloop-0.1.50/src/engine}/timer_entry.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/lib.rs +0 -2
- {rsloop-0.1.48 → rsloop-0.1.50}/src/module_init.rs +1 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/platform/fd/mod.rs +1 -34
- {rsloop-0.1.48 → rsloop-0.1.50}/src/platform/fd/windows.rs +1 -32
- {rsloop-0.1.48 → rsloop-0.1.50}/src/platform/mod.rs +0 -3
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/buffers.rs +91 -2
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/core_protocol.rs +114 -31
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/core_write.rs +124 -11
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/fast.rs +3 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/py_transport.rs +13 -3
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/write_queue.rs +8 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/blocking/default.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/driver/kqueue.rs +17 -2
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/driver/mio.rs +19 -9
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/fs/mod.rs +4 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/io/buf.rs +7 -3
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/io/splice.rs +2 -3
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/io/util.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/lib.rs +11 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/tcp/listener.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/tcp/mod.rs +16 -22
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/tcp/stream.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/udp.rs +5 -3
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/unix/mod.rs +16 -22
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/accept.rs +27 -20
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/accept_unix.rs +22 -16
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/connect.rs +84 -12
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/io_util.rs +44 -20
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/open.rs +2 -2
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/read.rs +58 -20
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/readv.rs +34 -37
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/recv.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/recvfrom.rs +23 -20
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/sendto.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/splice.rs +13 -4
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/waitpid.rs +1 -2
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/writeat.rs +1 -1
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/process/mod.rs +16 -3
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/process/reaper.rs +15 -7
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/signal/unix.rs +20 -21
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/signal/windows.rs +7 -16
- rsloop-0.1.50/src/vibeio/test_support.rs +281 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/time/sleep.rs +2 -2
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/time/timeout.rs +3 -6
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/timer.rs +41 -34
- rsloop-0.1.50/tests/test_benchmark_loops.py +127 -0
- rsloop-0.1.50/tests/test_buffered_delivery.py +102 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/test_compat.py +170 -176
- rsloop-0.1.50/tests/test_fast_callbacks.py +115 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/test_free_threading.py +10 -14
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/test_idle_benchmark.py +104 -93
- rsloop-0.1.50/tests/test_local_sockets.py +235 -0
- rsloop-0.1.50/tests/test_local_timers.py +90 -0
- rsloop-0.1.50/tests/test_numeric_addrinfo.py +126 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/test_run.py +119 -152
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/test_stream_reader.py +36 -43
- rsloop-0.1.50/tests/test_test_runner.py +87 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/test_tls.py +22 -29
- rsloop-0.1.50/tests/test_write_reentrancy.py +73 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/uv.lock +110 -42
- rsloop-0.1.48/src/bindings/loop_api/sock_ops.rs +0 -168
- rsloop-0.1.48/src/platform/windows_vibeio.rs +0 -180
- {rsloop-0.1.48 → rsloop-0.1.50}/.cargo/config.toml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.github/workflows/anyio.yml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.github/workflows/kani.yml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.github/workflows/mkdocs.yml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.github/workflows/update-version.yml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.github/workflows/wheels.yml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.gitignore +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.python-version +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/.vscode/settings.json +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/LICENSE +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/check_regression.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/idle_statistics.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/runtime.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/timer.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/benches/vibeio-performance.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/build.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/examples.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/getting-started.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/how-it-works.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/index.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/project-structure.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/rsloop.png +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/rust-extensions.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/verification.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/vibeio-cleanup.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/docs/vibeio-findings.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/01_basics.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/02_fd_and_sockets.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/03_streams.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/04_unix_and_accepted_socket.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/05_pipes_signals_subprocesses.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/README.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/fastapi_service.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/picows_server.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/picows_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/examples/wsbench_websockets.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/mkdocs.yml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/pyrightconfig.json +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/__init__.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/__init__.pyi +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/_bootstrap.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/_loop.pyi +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/_loop_compat.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/_profile.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/_run.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/python/rsloop/py.typed +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/rust-toolchain.toml +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/build-pgo-wheels.sh +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/build-wheels.sh +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/generate_test_tls_certs.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/prepare_anyio_rsloop_tests.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/python-versions.sh +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/scripts/run_rust_tests.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/async_event.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/asyncgens.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/asyncio_cache.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/connections.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/ffi_helpers.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/lifecycle.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/methods.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/pipes.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/pre_exec.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/process_handles.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/process_spawn.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/process_stdio.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/servers.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/signals.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/socket_connect.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/sockets.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/spawn_env.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/tasks.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/tls_params.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/bindings/loop_api/watchers.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/blocking.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/build_metadata.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/context.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/errors.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/profiler.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/python_names.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/rust_async.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/core_events.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/core_protocol.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/core_state.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/params.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/py_pipes.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/py_transport.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/spawn.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/process/worker.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/accept.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/builder.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/connect.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/core_events.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/core_state.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/io_targets.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/pipe_transport.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/platform.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/poll.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/protocol.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/py_server.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/reader.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/reader_task.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/server.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/server_core.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/server_types.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/socket_transport.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/stats.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/tls_session.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/tls_transport.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/tuning.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/worker.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/stream/writer.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/tls/material.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/transport/tls/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/verification.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/UPSTREAM.md +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/blocking/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/builder.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/driver/iocp.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/driver/mock.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/driver/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/driver/uring.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/executor.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/fd_inner.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/fs/file.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/fs/metadata.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/fs/open_options.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/io/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/io/pipe.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/io/stdio.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/unix/listener.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/net/unix/stream.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/fsync.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/hard_link.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/mkdir.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/readat.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/readiness.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/rename.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/send.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/socket_addr.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/statx.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/symlink.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/unlink.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/write.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/op/writev.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/signal/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/task.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/time/interval.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/time/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/util/async_wrap.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/src/vibeio/util/mod.rs +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/_smoke.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/aiohttp_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/anyio_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/beanie_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/daphne_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/django_asgi_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/django_orm_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/edgy_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/falcon_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/fastapi_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/faststream_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/hypercorn_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/litestar_granian_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/litestar_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/mangum_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/ormar_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/piccolo_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/quart_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/sanic_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/sqlalchemy_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/sqlmodel_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/starlette_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/tortoise_orm_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/packages/uvicorn_test.py +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/proptest-regressions/transport/stream/fast.txt +0 -0
- {rsloop-0.1.48 → rsloop-0.1.50}/tests/test_public_api.py +0 -0
|
@@ -62,54 +62,7 @@ jobs:
|
|
|
62
62
|
run: python3 scripts/run_rust_tests.py ${{ matrix.test_args }}
|
|
63
63
|
|
|
64
64
|
vibeio-native:
|
|
65
|
-
|
|
66
|
-
runs-on: ${{ matrix.os }}
|
|
67
|
-
timeout-minutes: 15
|
|
68
|
-
strategy:
|
|
69
|
-
fail-fast: false
|
|
70
|
-
matrix:
|
|
71
|
-
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
72
|
-
steps:
|
|
73
|
-
- name: Check out repository
|
|
74
|
-
uses: actions/checkout@v6
|
|
75
|
-
with:
|
|
76
|
-
persist-credentials: false
|
|
77
|
-
|
|
78
|
-
- name: Set up Rust
|
|
79
|
-
uses: dtolnay/rust-toolchain@stable
|
|
80
|
-
with:
|
|
81
|
-
toolchain: "1.98.1"
|
|
82
|
-
components: clippy, rustfmt
|
|
83
|
-
|
|
84
|
-
- name: Cache runtime harness build
|
|
85
|
-
uses: Swatinem/rust-cache@v2
|
|
86
|
-
with:
|
|
87
|
-
workspaces: tools/vibeio-check
|
|
88
|
-
|
|
89
|
-
- name: Check embedded runtime formatting
|
|
90
|
-
run: cargo fmt --manifest-path tools/vibeio-check/Cargo.toml --all -- --check
|
|
91
|
-
|
|
92
|
-
- name: Check embedded runtime documentation
|
|
93
|
-
env:
|
|
94
|
-
RUSTDOCFLAGS: -D warnings
|
|
95
|
-
run: cargo doc --manifest-path tools/vibeio-check/Cargo.toml --all-features --no-deps --locked
|
|
96
|
-
|
|
97
|
-
- name: Lint embedded runtime on the native target
|
|
98
|
-
run: cargo clippy --manifest-path tools/vibeio-check/Cargo.toml --all-targets --all-features --locked -- -D warnings
|
|
99
|
-
|
|
100
|
-
- name: Check isolated embedded runtime features
|
|
101
|
-
shell: bash
|
|
102
|
-
run: |
|
|
103
|
-
for feature in '' fs process signal pipe stdio splice blocking-default; do
|
|
104
|
-
cargo clippy --manifest-path tools/vibeio-check/Cargo.toml --all-targets --no-default-features --features "$feature" --locked -- -D warnings
|
|
105
|
-
cargo test --manifest-path tools/vibeio-check/Cargo.toml --no-default-features --features "$feature" --locked
|
|
106
|
-
done
|
|
107
|
-
|
|
108
|
-
- name: Run default-feature embedded runtime tests
|
|
109
|
-
run: cargo test --manifest-path tools/vibeio-check/Cargo.toml --locked
|
|
110
|
-
|
|
111
|
-
- name: Run all-feature embedded runtime tests
|
|
112
|
-
run: cargo test --manifest-path tools/vibeio-check/Cargo.toml --all-features --locked
|
|
65
|
+
uses: ./.github/workflows/vibeio-native.yml
|
|
113
66
|
|
|
114
67
|
clippy:
|
|
115
68
|
name: clippy (risk-focused)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
name: Vibeio native tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
repetitions:
|
|
7
|
+
description: "All-feature test repetitions per native platform"
|
|
8
|
+
type: choice
|
|
9
|
+
default: "3"
|
|
10
|
+
options: ["1", "3", "10"]
|
|
11
|
+
isolated_features:
|
|
12
|
+
description: "Also lint and test each feature independently"
|
|
13
|
+
type: boolean
|
|
14
|
+
default: true
|
|
15
|
+
workflow_call:
|
|
16
|
+
inputs:
|
|
17
|
+
repetitions:
|
|
18
|
+
type: string
|
|
19
|
+
default: "1"
|
|
20
|
+
isolated_features:
|
|
21
|
+
type: boolean
|
|
22
|
+
default: true
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
native:
|
|
29
|
+
name: vibeio (${{ matrix.os }})
|
|
30
|
+
runs-on: ${{ matrix.os }}
|
|
31
|
+
timeout-minutes: 30
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
36
|
+
defaults:
|
|
37
|
+
run:
|
|
38
|
+
shell: bash
|
|
39
|
+
env:
|
|
40
|
+
RUST_BACKTRACE: "1"
|
|
41
|
+
CARGO_TERM_COLOR: never
|
|
42
|
+
REPETITIONS: ${{ inputs.repetitions }}
|
|
43
|
+
steps:
|
|
44
|
+
- name: Check out repository
|
|
45
|
+
uses: actions/checkout@v6
|
|
46
|
+
with:
|
|
47
|
+
persist-credentials: false
|
|
48
|
+
|
|
49
|
+
- name: Set up Rust
|
|
50
|
+
uses: dtolnay/rust-toolchain@stable
|
|
51
|
+
with:
|
|
52
|
+
toolchain: "1.98.1"
|
|
53
|
+
components: clippy, rustfmt
|
|
54
|
+
|
|
55
|
+
- name: Cache runtime harness build
|
|
56
|
+
uses: Swatinem/rust-cache@v2
|
|
57
|
+
with:
|
|
58
|
+
workspaces: tools/vibeio-check
|
|
59
|
+
|
|
60
|
+
- name: Record native environment
|
|
61
|
+
run: |
|
|
62
|
+
mkdir -p target/vibeio-native-logs
|
|
63
|
+
case "$REPETITIONS" in
|
|
64
|
+
1|3|10) ;;
|
|
65
|
+
*) echo "Unsupported repetition count: $REPETITIONS"; exit 1 ;;
|
|
66
|
+
esac
|
|
67
|
+
{
|
|
68
|
+
git rev-parse HEAD
|
|
69
|
+
rustc -Vv
|
|
70
|
+
cargo -V
|
|
71
|
+
uname -a
|
|
72
|
+
} 2>&1 | tee target/vibeio-native-logs/environment.log
|
|
73
|
+
|
|
74
|
+
- name: Check formatting and documentation
|
|
75
|
+
env:
|
|
76
|
+
RUSTDOCFLAGS: -D warnings
|
|
77
|
+
run: |
|
|
78
|
+
cargo fmt --manifest-path tools/vibeio-check/Cargo.toml --all -- --check
|
|
79
|
+
cargo doc --manifest-path tools/vibeio-check/Cargo.toml --all-features --no-deps --locked 2>&1 | tee target/vibeio-native-logs/documentation.log
|
|
80
|
+
|
|
81
|
+
- name: Lint native all-feature build
|
|
82
|
+
run: cargo clippy --manifest-path tools/vibeio-check/Cargo.toml --all-targets --all-features --locked -- -D warnings 2>&1 | tee target/vibeio-native-logs/clippy.log
|
|
83
|
+
|
|
84
|
+
- name: Inventory native tests
|
|
85
|
+
run: cargo test --manifest-path tools/vibeio-check/Cargo.toml --all-features --locked -- --list 2>&1 | tee target/vibeio-native-logs/test-inventory.log
|
|
86
|
+
|
|
87
|
+
- name: Run native all-feature tests repeatedly
|
|
88
|
+
run: |
|
|
89
|
+
for ((iteration=1; iteration<=REPETITIONS; iteration++)); do
|
|
90
|
+
cargo test --manifest-path tools/vibeio-check/Cargo.toml --all-features --locked -- --nocapture 2>&1 | tee "target/vibeio-native-logs/all-features-${iteration}.log"
|
|
91
|
+
done
|
|
92
|
+
|
|
93
|
+
- name: Check isolated features
|
|
94
|
+
if: ${{ inputs.isolated_features }}
|
|
95
|
+
run: |
|
|
96
|
+
for feature in '' fs process signal pipe stdio splice blocking-default; do
|
|
97
|
+
label="${feature:-default}"
|
|
98
|
+
cargo clippy --manifest-path tools/vibeio-check/Cargo.toml --all-targets --no-default-features --features "$feature" --locked -- -D warnings 2>&1 | tee "target/vibeio-native-logs/clippy-${label}.log"
|
|
99
|
+
cargo test --manifest-path tools/vibeio-check/Cargo.toml --no-default-features --features "$feature" --locked -- --nocapture 2>&1 | tee "target/vibeio-native-logs/tests-${label}.log"
|
|
100
|
+
done
|
|
101
|
+
|
|
102
|
+
- name: Upload native test evidence
|
|
103
|
+
if: always()
|
|
104
|
+
uses: actions/upload-artifact@v4
|
|
105
|
+
with:
|
|
106
|
+
name: vibeio-native-${{ matrix.os }}-${{ github.run_attempt }}
|
|
107
|
+
path: target/vibeio-native-logs/
|
|
108
|
+
if-no-files-found: warn
|
|
109
|
+
retention-days: 14
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rsloop
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.50
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -496,10 +496,36 @@ The repository also includes:
|
|
|
496
496
|
|
|
497
497
|
```bash
|
|
498
498
|
uv run --with maturin maturin develop --release
|
|
499
|
-
uv run --with uvloop python benches/compare_event_loops.py
|
|
499
|
+
uv run --with uvloop --with 'zuvloop; python_version >= "3.14"' python benches/compare_event_loops.py \
|
|
500
|
+
--loops asyncio,uvloop,zuvloop,rsloop --repeat 7 --warmups 2
|
|
500
501
|
```
|
|
501
502
|
|
|
502
|
-
|
|
503
|
+
### Four-loop comparison on Linux
|
|
504
|
+
|
|
505
|
+
Measured on September 7, 2026 at commit `6cc3444` on an Intel Core i9-9900K,
|
|
506
|
+
Linux 7.0.0-31-generic (x86_64), and CPython 3.14.7, with rsloop 0.1.49 built
|
|
507
|
+
in release mode, uvloop 0.22.1, and zuvloop 0.0.14. Each entry is the median
|
|
508
|
+
of seven measured runs after two warmups, with each run in a fresh subprocess.
|
|
509
|
+
Times are milliseconds; lower is better.
|
|
510
|
+
|
|
511
|
+
| Workload | asyncio | uvloop | zuvloop | rsloop |
|
|
512
|
+
|---|---:|---:|---:|---:|
|
|
513
|
+
| 200,000 callbacks | 112.49 | 51.57 | **36.23** | 48.31 |
|
|
514
|
+
| 50,000 tasks | 149.49 | 93.55 | **81.47** | 89.54 |
|
|
515
|
+
| 5,000 TCP roundtrips | 150.87 | 126.20 | 109.64 | **84.60** |
|
|
516
|
+
|
|
517
|
+
The TCP workload uses 1,024-byte payloads and rsloop's native fast streams;
|
|
518
|
+
the other loops use stdlib asyncio streams. Use `--no-rsloop-fast-streams`
|
|
519
|
+
to compare all loops through the stdlib streams layer. Zuvloop led callbacks
|
|
520
|
+
and tasks in this run, while rsloop led TCP roundtrips. These are local
|
|
521
|
+
microbenchmarks, not isolated-lab measurements or general application performance
|
|
522
|
+
claims; do not compare them directly with the historical macOS results below.
|
|
523
|
+
See the [full report and recorded results](./benches/full-benchmark-6cc3444.md)
|
|
524
|
+
for the exact commands, build details, and process-run samples.
|
|
525
|
+
|
|
526
|
+
### Historical macOS comparison
|
|
527
|
+
|
|
528
|
+
An earlier example output from the script on macOS (arm64) with CPython 3.14:
|
|
503
529
|
|
|
504
530
|
```
|
|
505
531
|
callbacks (200,000 ops)
|
|
@@ -521,55 +547,59 @@ uvloop 0.133182 0.127404 37,543 31.5 MiB 1.46x
|
|
|
521
547
|
asyncio 0.302337 0.299813 16,538 29.6 MiB 3.32x 232.5%
|
|
522
548
|
```
|
|
523
549
|
|
|
550
|
+
### Sustained network workloads
|
|
551
|
+
|
|
524
552
|
The production-shaped workload matrix exercises HTTP, WebSocket libraries,
|
|
525
553
|
TLS, mixed message sizes, backpressure, and connection lifecycle behavior:
|
|
526
554
|
|
|
527
555
|
```bash
|
|
528
|
-
uv run --with uvloop python benches/workload_matrix.py \
|
|
529
|
-
--loops rsloop,uvloop \
|
|
556
|
+
uv run --with uvloop --with zuvloop python benches/workload_matrix.py \
|
|
557
|
+
--loops rsloop,uvloop,zuvloop \
|
|
530
558
|
--sustained \
|
|
531
|
-
--
|
|
559
|
+
--scenarios http_keepalive,tls_http,websocket_messages,websocket_tls,websockets_messages,websockets_tls,aiohttp_websocket_messages,aiohttp_websocket_tls,starlette_websocket_messages,starlette_websocket_tls,mixed_streams,bulk_transfer \
|
|
560
|
+
--json-output target/matrix-zuvloop.json
|
|
532
561
|
```
|
|
533
562
|
|
|
534
|
-
Measured on September
|
|
535
|
-
7.0.0-31-generic (x86_64), CPython 3.14.
|
|
536
|
-
uvloop 0.22.1. Each row reports the
|
|
537
|
-
warmups, using 16 concurrent connections
|
|
538
|
-
|
|
563
|
+
Measured on September 7, 2026 with an Intel Core i9-9900K, Linux
|
|
564
|
+
7.0.0-31-generic (x86_64), CPython 3.14.7, rsloop 0.1.49 (release build,
|
|
565
|
+
commit `6cc3444`), uvloop 0.22.1, and zuvloop 0.0.14. Each row reports the
|
|
566
|
+
median of seven measured runs after two warmups, using 16 concurrent connections.
|
|
567
|
+
Request/response workloads send 500 requests per connection; bulk transfer
|
|
568
|
+
sends 2 MiB per connection in 64 KiB chunks. Throughput is traffic-only
|
|
569
|
+
operations per second, except for
|
|
539
570
|
`bulk_transfer`, which reports traffic MiB/s. The p95 columns are the medians
|
|
540
|
-
of each run's p95 latency
|
|
571
|
+
of each run's p95 latency. Higher throughput and lower latency are better.
|
|
572
|
+
Each loop/scenario pair runs in its own subprocess, with warmups and measured
|
|
573
|
+
runs sharing that process. Loops run sequentially in the order shown.
|
|
541
574
|
|
|
542
575
|
WebSocket library versions were websockets 17.0.1, aiohttp 3.14.3, Starlette
|
|
543
576
|
1.6.0, and uvicorn 0.52.3. The run used unrestricted CPU affinity, with other
|
|
544
577
|
host services running but no concurrent builds or tests. These measurements
|
|
545
578
|
are from a different host than the macOS microbenchmark example above.
|
|
546
579
|
|
|
547
|
-
| Scenario | rsloop | uvloop |
|
|
548
|
-
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
549
|
-
| HTTP keep-alive |
|
|
550
|
-
| TLS HTTP | 72,
|
|
551
|
-
| Raw WebSocket |
|
|
552
|
-
| Raw WebSocket over TLS |
|
|
553
|
-
| `websockets` |
|
|
554
|
-
| `websockets` over TLS | 26,
|
|
555
|
-
| aiohttp WebSocket |
|
|
556
|
-
| aiohttp WebSocket over TLS |
|
|
557
|
-
| Starlette WebSocket | 18,
|
|
558
|
-
| Starlette WebSocket over TLS | 18,
|
|
559
|
-
| Mixed streams |
|
|
560
|
-
| Bulk transfer (MiB/s) | 1,
|
|
580
|
+
| Scenario | rsloop | uvloop | zuvloop | rsloop p95 | uvloop p95 | zuvloop p95 |
|
|
581
|
+
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
582
|
+
| HTTP keep-alive | 54,103 | 51,649 | 57,764 | 0.336 ms | 0.346 ms | 0.292 ms |
|
|
583
|
+
| TLS HTTP | 72,496 | 26,226 | 23,408 | 0.241 ms | 0.646 ms | 0.717 ms |
|
|
584
|
+
| Raw WebSocket | 4,870 | 4,890 | 4,898 | 4.454 ms | 3.874 ms | 3.357 ms |
|
|
585
|
+
| Raw WebSocket over TLS | 4,933 | 4,455 | 4,397 | 4.355 ms | 4.194 ms | 3.800 ms |
|
|
586
|
+
| `websockets` | 24,667 | 25,800 | 27,409 | 0.736 ms | 0.631 ms | 0.594 ms |
|
|
587
|
+
| `websockets` over TLS | 26,781 | 14,872 | 14,555 | 0.644 ms | 1.135 ms | 1.167 ms |
|
|
588
|
+
| aiohttp WebSocket | 31,636 | 32,765 | 35,425 | 0.605 ms | 0.535 ms | 0.484 ms |
|
|
589
|
+
| aiohttp WebSocket over TLS | 34,165 | 19,110 | 18,400 | 0.504 ms | 0.882 ms | 0.909 ms |
|
|
590
|
+
| Starlette WebSocket | 18,785 | 20,407 | 21,743 | 0.981 ms | 0.829 ms | 0.787 ms |
|
|
591
|
+
| Starlette WebSocket over TLS | 18,509 | 13,104 | 13,038 | 0.948 ms | 1.278 ms | 1.291 ms |
|
|
592
|
+
| Mixed streams | 43,795 | 34,196 | 37,116 | 0.463 ms | 0.523 ms | 0.473 ms |
|
|
593
|
+
| Bulk transfer (MiB/s) | 2,009.9 | 1,264.9 | 1,313.3 | 15.058 ms | 25.219 ms | 24.317 ms |
|
|
561
594
|
|
|
562
595
|
The former single-burst idle-activation row has been retired: its traffic
|
|
563
596
|
phase lasted only a few milliseconds and produced unstable throughput rankings.
|
|
564
597
|
Idle activation now has a separate, versioned latency benchmark described below.
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
19.4%, and 22.3%, respectively. They still trail uvloop. The historical regression
|
|
571
|
-
gate also flagged HTTP tail latency and legacy idle activation; this is not an
|
|
572
|
-
across-the-board performance win. See the
|
|
598
|
+
In this run, zuvloop had the highest plaintext HTTP and WebSocket throughput,
|
|
599
|
+
while rsloop led TLS throughput, mixed streams, and bulk transfer. Throughput
|
|
600
|
+
and tail latency do not always agree: rsloop's raw WebSocket p95 was higher
|
|
601
|
+
than both alternatives, including over TLS. These results are not an
|
|
602
|
+
across-the-board performance win or a before/after regression measurement. See the
|
|
573
603
|
[benchmark documentation](./benches/README.md) for workload definitions and
|
|
574
604
|
reproduction commands.
|
|
575
605
|
|
|
@@ -582,41 +612,50 @@ so has more to lose when cores are contended.
|
|
|
582
612
|
### Idle activation latency
|
|
583
613
|
|
|
584
614
|
```bash
|
|
585
|
-
|
|
586
|
-
--loops rsloop,uvloop --scenarios idle_connections --repeat
|
|
615
|
+
uv run --with uvloop --with zuvloop python benches/workload_matrix.py \
|
|
616
|
+
--loops rsloop,uvloop,zuvloop --scenarios idle_connections --repeat 9 \
|
|
587
617
|
--idle-cycles 100 --idle-warmup-cycles 5 --idle-seconds 0.2 \
|
|
588
618
|
--json-output target/idle-v2-paired.json
|
|
589
619
|
```
|
|
590
620
|
|
|
591
621
|
Idle v2 reuses 200 established connections across repeated idle/wakeup cycles.
|
|
592
622
|
It measures all replies from one shared activation timestamp, including task
|
|
593
|
-
scheduling delay, and reports first/50%/95%/all-reply latency.
|
|
594
|
-
blocks
|
|
623
|
+
scheduling delay, and reports first/50%/95%/all-reply latency. Nine fresh-process
|
|
624
|
+
blocks rotate loop order so each loop runs first three times; confidence intervals resample whole paired runs,
|
|
595
625
|
not individual connections. Results are classified as improved, regressed, or
|
|
596
626
|
inconclusive using a 5% practical threshold and an approximate 95% confidence
|
|
597
|
-
interval. The command takes about
|
|
627
|
+
interval. The command takes about ten minutes; use `--idle-cycles 3
|
|
598
628
|
--idle-warmup-cycles 1 --idle-seconds 0.01 --repeat 1` for a smoke test only.
|
|
599
629
|
|
|
600
630
|
The new measurements cannot be compared with the retired ops/s row. See
|
|
601
631
|
[benchmark methodology and regression handling](./benches/README.md#idle-activation-v2)
|
|
602
632
|
for timing definitions, host controls, raw distributions, and sample requirements.
|
|
603
633
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
634
|
+
Measured on September 7, 2026 at commit `6cc3444` on the Linux/i9-9900K
|
|
635
|
+
host above with CPython 3.14.7, rsloop 0.1.49 (release), uvloop 0.22.1,
|
|
636
|
+
and zuvloop 0.0.14. The run collected 900 measured cycles per loop in 27
|
|
637
|
+
distinct processes, with unrestricted affinity and no concurrent builds or
|
|
638
|
+
test runs. These are medians across runs of each run's median cycle milestone,
|
|
639
|
+
in milliseconds (lower is better):
|
|
608
640
|
|
|
609
641
|
| Loop | First reply | 50% replied | 95% replied | All replied |
|
|
610
642
|
| --- | ---: | ---: | ---: | ---: |
|
|
611
|
-
| rsloop | 17.
|
|
612
|
-
| uvloop | 18.
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
643
|
+
| rsloop | 17.221 | 17.579 | 17.857 | 17.991 |
|
|
644
|
+
| uvloop | 18.193 | 18.722 | 19.174 | 19.221 |
|
|
645
|
+
| zuvloop | 16.441 | 16.869 | 17.248 | 17.288 |
|
|
646
|
+
|
|
647
|
+
Comparisons against uvloop use geometric mean paired process-run ratios,
|
|
648
|
+
not ratios of the table medians:
|
|
649
|
+
|
|
650
|
+
- rsloop: -23.5% p95 latency, approximate 95% interval [-48.6%, +5.9%]; **inconclusive** at the 5% threshold.
|
|
651
|
+
- zuvloop: -15.2% p95 latency, approximate 95% interval [-31.0%, +4.5%]; **inconclusive** at the 5% threshold.
|
|
652
|
+
|
|
653
|
+
Individual cycle-p95 latencies span 3.374–28.184 ms for rsloop,
|
|
654
|
+
3.736–24.228 ms for uvloop, and 3.454–26.163 ms for zuvloop.
|
|
655
|
+
Median ordering alone does not establish a latency win.
|
|
656
|
+
|
|
657
|
+
The [full report](./benches/full-benchmark-6cc3444.md) links the recorded
|
|
658
|
+
measurements and documents the settings used for all three benchmark suites.
|
|
620
659
|
|
|
621
660
|
See [`benches/README.md`](./benches/README.md) for workload details and
|
|
622
661
|
extra flags, and [`examples/README.md`](./examples/README.md) for the FastAPI
|
|
@@ -464,10 +464,36 @@ The repository also includes:
|
|
|
464
464
|
|
|
465
465
|
```bash
|
|
466
466
|
uv run --with maturin maturin develop --release
|
|
467
|
-
uv run --with uvloop python benches/compare_event_loops.py
|
|
467
|
+
uv run --with uvloop --with 'zuvloop; python_version >= "3.14"' python benches/compare_event_loops.py \
|
|
468
|
+
--loops asyncio,uvloop,zuvloop,rsloop --repeat 7 --warmups 2
|
|
468
469
|
```
|
|
469
470
|
|
|
470
|
-
|
|
471
|
+
### Four-loop comparison on Linux
|
|
472
|
+
|
|
473
|
+
Measured on September 7, 2026 at commit `6cc3444` on an Intel Core i9-9900K,
|
|
474
|
+
Linux 7.0.0-31-generic (x86_64), and CPython 3.14.7, with rsloop 0.1.49 built
|
|
475
|
+
in release mode, uvloop 0.22.1, and zuvloop 0.0.14. Each entry is the median
|
|
476
|
+
of seven measured runs after two warmups, with each run in a fresh subprocess.
|
|
477
|
+
Times are milliseconds; lower is better.
|
|
478
|
+
|
|
479
|
+
| Workload | asyncio | uvloop | zuvloop | rsloop |
|
|
480
|
+
|---|---:|---:|---:|---:|
|
|
481
|
+
| 200,000 callbacks | 112.49 | 51.57 | **36.23** | 48.31 |
|
|
482
|
+
| 50,000 tasks | 149.49 | 93.55 | **81.47** | 89.54 |
|
|
483
|
+
| 5,000 TCP roundtrips | 150.87 | 126.20 | 109.64 | **84.60** |
|
|
484
|
+
|
|
485
|
+
The TCP workload uses 1,024-byte payloads and rsloop's native fast streams;
|
|
486
|
+
the other loops use stdlib asyncio streams. Use `--no-rsloop-fast-streams`
|
|
487
|
+
to compare all loops through the stdlib streams layer. Zuvloop led callbacks
|
|
488
|
+
and tasks in this run, while rsloop led TCP roundtrips. These are local
|
|
489
|
+
microbenchmarks, not isolated-lab measurements or general application performance
|
|
490
|
+
claims; do not compare them directly with the historical macOS results below.
|
|
491
|
+
See the [full report and recorded results](./benches/full-benchmark-6cc3444.md)
|
|
492
|
+
for the exact commands, build details, and process-run samples.
|
|
493
|
+
|
|
494
|
+
### Historical macOS comparison
|
|
495
|
+
|
|
496
|
+
An earlier example output from the script on macOS (arm64) with CPython 3.14:
|
|
471
497
|
|
|
472
498
|
```
|
|
473
499
|
callbacks (200,000 ops)
|
|
@@ -489,55 +515,59 @@ uvloop 0.133182 0.127404 37,543 31.5 MiB 1.46x
|
|
|
489
515
|
asyncio 0.302337 0.299813 16,538 29.6 MiB 3.32x 232.5%
|
|
490
516
|
```
|
|
491
517
|
|
|
518
|
+
### Sustained network workloads
|
|
519
|
+
|
|
492
520
|
The production-shaped workload matrix exercises HTTP, WebSocket libraries,
|
|
493
521
|
TLS, mixed message sizes, backpressure, and connection lifecycle behavior:
|
|
494
522
|
|
|
495
523
|
```bash
|
|
496
|
-
uv run --with uvloop python benches/workload_matrix.py \
|
|
497
|
-
--loops rsloop,uvloop \
|
|
524
|
+
uv run --with uvloop --with zuvloop python benches/workload_matrix.py \
|
|
525
|
+
--loops rsloop,uvloop,zuvloop \
|
|
498
526
|
--sustained \
|
|
499
|
-
--
|
|
527
|
+
--scenarios http_keepalive,tls_http,websocket_messages,websocket_tls,websockets_messages,websockets_tls,aiohttp_websocket_messages,aiohttp_websocket_tls,starlette_websocket_messages,starlette_websocket_tls,mixed_streams,bulk_transfer \
|
|
528
|
+
--json-output target/matrix-zuvloop.json
|
|
500
529
|
```
|
|
501
530
|
|
|
502
|
-
Measured on September
|
|
503
|
-
7.0.0-31-generic (x86_64), CPython 3.14.
|
|
504
|
-
uvloop 0.22.1. Each row reports the
|
|
505
|
-
warmups, using 16 concurrent connections
|
|
506
|
-
|
|
531
|
+
Measured on September 7, 2026 with an Intel Core i9-9900K, Linux
|
|
532
|
+
7.0.0-31-generic (x86_64), CPython 3.14.7, rsloop 0.1.49 (release build,
|
|
533
|
+
commit `6cc3444`), uvloop 0.22.1, and zuvloop 0.0.14. Each row reports the
|
|
534
|
+
median of seven measured runs after two warmups, using 16 concurrent connections.
|
|
535
|
+
Request/response workloads send 500 requests per connection; bulk transfer
|
|
536
|
+
sends 2 MiB per connection in 64 KiB chunks. Throughput is traffic-only
|
|
537
|
+
operations per second, except for
|
|
507
538
|
`bulk_transfer`, which reports traffic MiB/s. The p95 columns are the medians
|
|
508
|
-
of each run's p95 latency
|
|
539
|
+
of each run's p95 latency. Higher throughput and lower latency are better.
|
|
540
|
+
Each loop/scenario pair runs in its own subprocess, with warmups and measured
|
|
541
|
+
runs sharing that process. Loops run sequentially in the order shown.
|
|
509
542
|
|
|
510
543
|
WebSocket library versions were websockets 17.0.1, aiohttp 3.14.3, Starlette
|
|
511
544
|
1.6.0, and uvicorn 0.52.3. The run used unrestricted CPU affinity, with other
|
|
512
545
|
host services running but no concurrent builds or tests. These measurements
|
|
513
546
|
are from a different host than the macOS microbenchmark example above.
|
|
514
547
|
|
|
515
|
-
| Scenario | rsloop | uvloop |
|
|
516
|
-
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
517
|
-
| HTTP keep-alive |
|
|
518
|
-
| TLS HTTP | 72,
|
|
519
|
-
| Raw WebSocket |
|
|
520
|
-
| Raw WebSocket over TLS |
|
|
521
|
-
| `websockets` |
|
|
522
|
-
| `websockets` over TLS | 26,
|
|
523
|
-
| aiohttp WebSocket |
|
|
524
|
-
| aiohttp WebSocket over TLS |
|
|
525
|
-
| Starlette WebSocket | 18,
|
|
526
|
-
| Starlette WebSocket over TLS | 18,
|
|
527
|
-
| Mixed streams |
|
|
528
|
-
| Bulk transfer (MiB/s) | 1,
|
|
548
|
+
| Scenario | rsloop | uvloop | zuvloop | rsloop p95 | uvloop p95 | zuvloop p95 |
|
|
549
|
+
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
550
|
+
| HTTP keep-alive | 54,103 | 51,649 | 57,764 | 0.336 ms | 0.346 ms | 0.292 ms |
|
|
551
|
+
| TLS HTTP | 72,496 | 26,226 | 23,408 | 0.241 ms | 0.646 ms | 0.717 ms |
|
|
552
|
+
| Raw WebSocket | 4,870 | 4,890 | 4,898 | 4.454 ms | 3.874 ms | 3.357 ms |
|
|
553
|
+
| Raw WebSocket over TLS | 4,933 | 4,455 | 4,397 | 4.355 ms | 4.194 ms | 3.800 ms |
|
|
554
|
+
| `websockets` | 24,667 | 25,800 | 27,409 | 0.736 ms | 0.631 ms | 0.594 ms |
|
|
555
|
+
| `websockets` over TLS | 26,781 | 14,872 | 14,555 | 0.644 ms | 1.135 ms | 1.167 ms |
|
|
556
|
+
| aiohttp WebSocket | 31,636 | 32,765 | 35,425 | 0.605 ms | 0.535 ms | 0.484 ms |
|
|
557
|
+
| aiohttp WebSocket over TLS | 34,165 | 19,110 | 18,400 | 0.504 ms | 0.882 ms | 0.909 ms |
|
|
558
|
+
| Starlette WebSocket | 18,785 | 20,407 | 21,743 | 0.981 ms | 0.829 ms | 0.787 ms |
|
|
559
|
+
| Starlette WebSocket over TLS | 18,509 | 13,104 | 13,038 | 0.948 ms | 1.278 ms | 1.291 ms |
|
|
560
|
+
| Mixed streams | 43,795 | 34,196 | 37,116 | 0.463 ms | 0.523 ms | 0.473 ms |
|
|
561
|
+
| Bulk transfer (MiB/s) | 2,009.9 | 1,264.9 | 1,313.3 | 15.058 ms | 25.219 ms | 24.317 ms |
|
|
529
562
|
|
|
530
563
|
The former single-burst idle-activation row has been retired: its traffic
|
|
531
564
|
phase lasted only a few milliseconds and produced unstable throughput rankings.
|
|
532
565
|
Idle activation now has a separate, versioned latency benchmark described below.
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
19.4%, and 22.3%, respectively. They still trail uvloop. The historical regression
|
|
539
|
-
gate also flagged HTTP tail latency and legacy idle activation; this is not an
|
|
540
|
-
across-the-board performance win. See the
|
|
566
|
+
In this run, zuvloop had the highest plaintext HTTP and WebSocket throughput,
|
|
567
|
+
while rsloop led TLS throughput, mixed streams, and bulk transfer. Throughput
|
|
568
|
+
and tail latency do not always agree: rsloop's raw WebSocket p95 was higher
|
|
569
|
+
than both alternatives, including over TLS. These results are not an
|
|
570
|
+
across-the-board performance win or a before/after regression measurement. See the
|
|
541
571
|
[benchmark documentation](./benches/README.md) for workload definitions and
|
|
542
572
|
reproduction commands.
|
|
543
573
|
|
|
@@ -550,41 +580,50 @@ so has more to lose when cores are contended.
|
|
|
550
580
|
### Idle activation latency
|
|
551
581
|
|
|
552
582
|
```bash
|
|
553
|
-
|
|
554
|
-
--loops rsloop,uvloop --scenarios idle_connections --repeat
|
|
583
|
+
uv run --with uvloop --with zuvloop python benches/workload_matrix.py \
|
|
584
|
+
--loops rsloop,uvloop,zuvloop --scenarios idle_connections --repeat 9 \
|
|
555
585
|
--idle-cycles 100 --idle-warmup-cycles 5 --idle-seconds 0.2 \
|
|
556
586
|
--json-output target/idle-v2-paired.json
|
|
557
587
|
```
|
|
558
588
|
|
|
559
589
|
Idle v2 reuses 200 established connections across repeated idle/wakeup cycles.
|
|
560
590
|
It measures all replies from one shared activation timestamp, including task
|
|
561
|
-
scheduling delay, and reports first/50%/95%/all-reply latency.
|
|
562
|
-
blocks
|
|
591
|
+
scheduling delay, and reports first/50%/95%/all-reply latency. Nine fresh-process
|
|
592
|
+
blocks rotate loop order so each loop runs first three times; confidence intervals resample whole paired runs,
|
|
563
593
|
not individual connections. Results are classified as improved, regressed, or
|
|
564
594
|
inconclusive using a 5% practical threshold and an approximate 95% confidence
|
|
565
|
-
interval. The command takes about
|
|
595
|
+
interval. The command takes about ten minutes; use `--idle-cycles 3
|
|
566
596
|
--idle-warmup-cycles 1 --idle-seconds 0.01 --repeat 1` for a smoke test only.
|
|
567
597
|
|
|
568
598
|
The new measurements cannot be compared with the retired ops/s row. See
|
|
569
599
|
[benchmark methodology and regression handling](./benches/README.md#idle-activation-v2)
|
|
570
600
|
for timing definitions, host controls, raw distributions, and sample requirements.
|
|
571
601
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
602
|
+
Measured on September 7, 2026 at commit `6cc3444` on the Linux/i9-9900K
|
|
603
|
+
host above with CPython 3.14.7, rsloop 0.1.49 (release), uvloop 0.22.1,
|
|
604
|
+
and zuvloop 0.0.14. The run collected 900 measured cycles per loop in 27
|
|
605
|
+
distinct processes, with unrestricted affinity and no concurrent builds or
|
|
606
|
+
test runs. These are medians across runs of each run's median cycle milestone,
|
|
607
|
+
in milliseconds (lower is better):
|
|
576
608
|
|
|
577
609
|
| Loop | First reply | 50% replied | 95% replied | All replied |
|
|
578
610
|
| --- | ---: | ---: | ---: | ---: |
|
|
579
|
-
| rsloop | 17.
|
|
580
|
-
| uvloop | 18.
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
611
|
+
| rsloop | 17.221 | 17.579 | 17.857 | 17.991 |
|
|
612
|
+
| uvloop | 18.193 | 18.722 | 19.174 | 19.221 |
|
|
613
|
+
| zuvloop | 16.441 | 16.869 | 17.248 | 17.288 |
|
|
614
|
+
|
|
615
|
+
Comparisons against uvloop use geometric mean paired process-run ratios,
|
|
616
|
+
not ratios of the table medians:
|
|
617
|
+
|
|
618
|
+
- rsloop: -23.5% p95 latency, approximate 95% interval [-48.6%, +5.9%]; **inconclusive** at the 5% threshold.
|
|
619
|
+
- zuvloop: -15.2% p95 latency, approximate 95% interval [-31.0%, +4.5%]; **inconclusive** at the 5% threshold.
|
|
620
|
+
|
|
621
|
+
Individual cycle-p95 latencies span 3.374–28.184 ms for rsloop,
|
|
622
|
+
3.736–24.228 ms for uvloop, and 3.454–26.163 ms for zuvloop.
|
|
623
|
+
Median ordering alone does not establish a latency win.
|
|
624
|
+
|
|
625
|
+
The [full report](./benches/full-benchmark-6cc3444.md) links the recorded
|
|
626
|
+
measurements and documents the settings used for all three benchmark suites.
|
|
588
627
|
|
|
589
628
|
See [`benches/README.md`](./benches/README.md) for workload details and
|
|
590
629
|
extra flags, and [`examples/README.md`](./examples/README.md) for the FastAPI
|