1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
//! A crate with helper functions that execute given closures in parallel on all available processors. #![doc(html_root_url = "https://docs.rs/mth_calc/0.1.1")] use std::thread; /// Runs a given closure in parallel on all available CPUs. /// /// The given closure can return a value. All return values of all closure executions are /// aggregated with a given aggregation closure. The method returns a tuple with /// the aggregated result and the number of executions (=number of CPUs). /// /// # Arguments /// /// * `body` - closure that should be run in parallel on all available processors. /// * `initial` - initial value used for aggregating the results of all closure executions. /// * `agg` - closure used to aggregate method results. /// /// # Examples /// /// ``` /// use mth_calc::run_on_all_cpus; /// use rand::prelude::*; /// /// let result = mth_calc::run_on_all_cpus::<f32>(|| { /// // Create a thread-local random generator /// let mut rng = thread_rng(); /// /// // Calculate sum over ten random numbers /// let mut total = 0f32; /// for _ in 0..10 { /// total += rng.gen::<f32>(); /// } /// /// total /// }, /// 0f32, // initial value for aggreation is zero /// |x, y| { x + y }); // aggregation function = sum /// /// let avg = result.0 / (result.1 * 10) as f32; /// # if avg < 0f32 || avg >= 1f32 { /// # panic!(); /// # } /// println!("The average random number was {}", avg); /// ``` pub fn run_on_all_cpus<T: Send + 'static>(body: fn() -> T, initial: T, agg: fn(T, T) -> T) -> (T, u32) { // Start one thread per CPU let num_cpus = num_cpus::get() as u32; let mut handles = vec!(); for _ in 0..num_cpus { handles.push(thread::spawn(body)); } // Wait for all threads to complete and summarize // their results. let mut result = initial; for h in handles { result = agg(result, h.join().unwrap()); } (result, num_cpus) } #[cfg(test)] mod tests { use super::*; #[test] fn it_calculates_result_correctly() { let result = run_on_all_cpus(|| { 1 }, 0, |a, b| { a + b }); if result.0 < 1 || result.1 < 1 || result.0 / result.1 != 1 { panic!(); } } }