You've currently got what's called imperative code; it cannot be directly changed into parallel without going through a functional style:
pub fn search_max(array: &[f32], start: i32, end: i32) -> f32 {
let sub_array: &[f32] = &array[start as usize..end as usize];
*sub_array.iter().max().unwrap()
}
We use the max
method to get the maximum value produced by the iterator. This does not work since f32
cannot be guaranteed to order nicely.
We'll use max_by
instead with a closure:
pub fn search_max(array: &[f32], start: i32, end: i32) -> f32 {
let sub_array: &[f32] = &array[start as usize..end as usize];
* // This results in &f32, so we must dereference it
sub_array.iter() // Create the iterator over references to the items
.max_by(
|x, y| x.partial_cmp(y).unwrap() // https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html#tymethod.partial_cmp
).unwrap() // There could possibly be no items! So we get an `Option<&f32>` instead.
}
For the most part, rayon
's ParallelIterator
is a drop in replacement for a regular iterator, so anywhere we see .iter
we change to .par_iter
:
use rayon::prelude::*;
pub fn search_max(array: &[f32], start: i32, end: i32) -> f32 {
let sub_array: &[f32] = &array[start as usize..end as usize];
*sub_array.par_iter().max_by(|x, y| x.partial_cmp(y).unwrap()).unwrap()
}
Playground
If you're looking for the most idiomatic version of this:
pub fn search_max(slice: &'_ [f32], start: usize, end: usize) -> f32 {
*slice[start..end].par_iter().reduce(
|| &slice[start], // This is an iterator over &'_ f32
|a, b| if a > b { a } else { b },
)
}
Playground