From 5499bc305826fc0401a8911026c45d7d621049a1 Mon Sep 17 00:00:00 2001 From: Nikolai Vazquez Date: Wed, 27 Nov 2024 20:32:12 -0500 Subject: [PATCH] Reduce thread pool memory usage The array-based channel that was created for a capacity of 1 would allocate many more kilobytes than waiting for the auxiliary thread to accept the task. --- CHANGELOG.md | 5 +++++ src/thread_pool.rs | 21 ++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d731156..3f8e173 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed + +- Reduced thread pool memory usage by many kilobytes by using rendezvous + channels instead of array-based channels. + ## [0.1.16] - 2024-11-25 ### Added diff --git a/src/thread_pool.rs b/src/thread_pool.rs index a1ff277..c607a93 100644 --- a/src/thread_pool.rs +++ b/src/thread_pool.rs @@ -223,14 +223,13 @@ fn spawn(additional: NonZeroUsize, threads: &mut Vec>) { let next_thread_id = threads.len() + 1; threads.extend((next_thread_id..(next_thread_id + additional.get())).map(|thread_id| { - // Create single-task channel. + // Create single-task channel. Unless another benchmark is running, the + // current thread will be immediately unblocked after the auxiliary + // thread accepts the task. // - // If we used 0 (rendezvous channel), then the main thread would block - // while sending a task until the auxiliary thread accepts the task. - // Using a capacity of 1 allows the main thread to immediately progress - // onto finishing its local work, including sending the task to all - // remaining threads. - let (sender, receiver) = mpsc::sync_channel::(1); + // This uses a rendezvous channel (capacity 0) instead of other standard + // library channels because it reduces memory usage by many kilobytes. + let (sender, receiver) = mpsc::sync_channel::(0); let work = move || { // Abort the process if the caught panic error itself panics when @@ -379,4 +378,12 @@ mod benches { bencher.bench(benched); } + + /// Benchmarks using `ThreadPool` once. + #[crate::bench(crate = crate, args = aux_thread_counts(), sample_size = 1)] + fn broadcast_once(bencher: crate::Bencher, aux_threads: usize) { + bencher + .with_inputs(ThreadPool::new) + .bench_refs(|pool| pool.broadcast(aux_threads, crate::black_box_drop)); + } }