diff --git a/README.md b/README.md index c323832..a2becb7 100644 --- a/README.md +++ b/README.md @@ -65,13 +65,15 @@ algorithms in Rust and benchmark them. Let the battle begin. - `single thread`: No multi-threading or any optimization of any kind. Used as a reference. +- `lpt`: Manual multi-threading. Tasks are sorted so the shortest ones are + executed first. This is the [longest-processing-time-first algorithm][lpt]. - `rayon`: Multi-threading provided by the `rayon` crate, but no optimization of any kind. Used as a reference. - `rayon sorted`: Multi-threading provided by the `rayon` crate. Tasks are sorted so the shortest ones are executed first. - `rayon sorted reverse`: Multi-threading provided by the `rayon` crate. Tasks are sorted so the longest ones are executed first. This should behave as an - [LPT][lpt]. + LPT. - `rayon sorted reverse`: Similar to `rayon sorted reverse`, but tasks are sorted from shortest to longest and are then iterated in the reverse order. diff --git a/benches/job_scheduling.rs b/benches/job_scheduling.rs index 8fb62c1..8d8ef53 100644 --- a/benches/job_scheduling.rs +++ b/benches/job_scheduling.rs @@ -6,6 +6,7 @@ use rust_job_scheduling::Task; const TEST_DATA: &[(&str, &[Task])] = &[("10 tasks", T_10), ("500 tasks", T_500)]; const TEST_FUNCS: &[(&str, &dyn Fn(&[Task]))] = &[ ("single thread", &single_thread), + ("lpt", &lpt), ("rayon", &rayon), ("rayon sorted", &rayon_sorted), ("rayon sorted reverse", &rayon_sorted_reverse), diff --git a/src/algorithm.rs b/src/algorithm.rs index f75d047..e46e616 100644 --- a/src/algorithm.rs +++ b/src/algorithm.rs @@ -1,5 +1,7 @@ +mod lpt; mod rayon; mod single_thread; +pub use lpt::lpt; pub use rayon::*; pub use single_thread::single_thread; diff --git a/src/algorithm/lpt.rs b/src/algorithm/lpt.rs new file mode 100644 index 0000000..237d493 --- /dev/null +++ b/src/algorithm/lpt.rs @@ -0,0 +1,33 @@ +use crate::Task; +use std::sync::{Arc, Mutex}; +use std::thread; + +pub fn lpt(data: &[Task]) { + let mut data = data.to_vec(); + data.sort(); + + let data_mt = Arc::new(Mutex::new(data)); + let nb_threads = thread::available_parallelism() + .map(|n| n.get()) + .unwrap_or(1); + let mut handles = Vec::with_capacity(nb_threads); + + for _ in 0..nb_threads { + let dt = data_mt.clone(); + let h = thread::spawn(move || loop { + let mut data = dt.lock().unwrap(); + let task = match data.pop() { + Some(t) => t, + None => { + break; + } + }; + std::mem::drop(data); + task.execute(); + }); + handles.push(h); + } + for h in handles { + let _ = h.join(); + } +}