Repository navigation
perf(runtime): cap the default runtime at four worker threads - #200
Merged
Merged
Conversation
Runtime::new() starts one worker per logical CPU, so the shared runtime the app and the service run on starts 32 workers on a 32-thread machine. Measured in the app, worker counts above four added threads and private memory without lowering timer lateness under load or CPU time, while one worker let a single blocking operation stall the whole runtime for seconds. Start one worker per available CPU but at most four, and one when the parallelism cannot be queried. The explicit count overrides the TOKIO_WORKER_THREADS environment variable.
This was referenced Oct 17, 2026
chore(submodule): bump nyanpasu-utils to cap runtime worker threads
libnyanpasu/nyanpasu-runtime#446
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
default_runtime()usedRuntime::new(), which starts one worker per logical CPU. The app hands this runtime to Tauri, andnyanpasu-serviceruns on it throughruntime::block_on, so on a 32-thread machine both start 32 workers.The app was measured on Windows 11 with 32 logical CPUs: a profiling build of app main, six instances run concurrently under the same synthetic proxy load with
TOKIO_WORKER_THREADS= 1/2/4/8/16/32. Each ran 37 min in the background with the window closed, then 16 min with the window open while scripted RPC operations looped.CPU time showed no trend across worker counts. Above four workers the extra threads and memory bought nothing. With one worker, a single blocking operation stalled the runtime: collecting the environment took 3.8 s, profile activation 650–740 ms and a core restart 711 ms, and reading a 5.5 MB profile 213 ms. With two or more workers each of these operations stayed at or under 17 ms. Two workers still stalled for 103 ms when blocking operations overlapped, so four leaves headroom. Those blocking call sites belong in
spawn_blocking, and the app will move them in a separate change.Change
When
available_parallelism()fails, the runtime starts one worker. Apart from the worker count it is configured asRuntime::new()was: multi-thread, with every driver enabled.TOKIO_WORKER_THREADSis no longer honoured by this runtime, becauseBuilder::worker_threadstakes precedence over it. Supporting it again would mean parsing the variable here as well. Nothing in the app or the runtime sets it; it was only used for the measurement above.A unit test checks that the default runtime starts between one and
MAX_WORKER_THREADSworkers. On a machine with more than four CPUs it fails against the oldRuntime::new().Downstream
Not tested
cargo clippy -p nyanpasu-utils --all-targets --all-featuresand the new unit test were run inside the nyanpasu-runtime workspace on Windows. The standalone CI run of this repository was not reproduced locally.nyanpasu-serviceunder load was not measured with the cap.