Struct Reducer

Source
pub struct Reducer<G: Debug + Default, L: Debug + Default = G> { /* private fields */ }
Expand description

An OpenMP-style reducer that wraps a global value into a Mutex, providing shareable, cloneable copies with a local value; the copies will be reduced into the global value when dropped.

The global value can be observed with peek if the base type is Clone, whereas get consumes self and returns the global value.

For convenience, the global value and the local value have distinct type parameters G and L, respectively; the second type defaults to the first one.

Each shared copy has a reference to the Reducer it was created from, so you cannot call get if there are still shared copies around. For example, this code will not compile:

use openmp_reducer::Reducer;

let reducer = Reducer::<usize>::new(3, |global, local| *global += *local);
let mut shared = reducer.share();
// drop(shared); // uncommenting this line would make the code compile
assert_eq!(reducer.get(), 3);

§Examples

In this example, we manually spawn processes:

use openmp_reducer::Reducer;
use std::thread;

let mut reducer = Reducer::<usize>::new(5, |global, local| *global += *local);
std::thread::scope(|s| {
    for i in 0..3 {
        let mut shared = reducer.share();
        s.spawn(move || {
            *shared.as_mut() += 10;
        });
    }
});

// Initial value plus additional values from shared copies
assert_eq!(reducer.get(), 35);

You can obtain the same behavior with Rayon using methods such as for_each_with and map_with:

use openmp_reducer::Reducer;
use rayon::prelude::*;

let mut reducer = Reducer::<usize>::new(5, |global, local| *global += *local);
(0..1000000).into_par_iter().
    with_min_len(1000). // optional, might reduce the amount of cloning
    for_each_with(reducer.share(), |shared, i| {
        *shared.as_mut() += 1;
    }
);

// Initial value plus additional values from clones
assert_eq!(reducer.get(), 1_000_005);

Note that you have to pass reducer.share(), which can be cloned. Also, since for_each_with might perform excessive cloning if jobs are too short, you can use with_min_len to reduce the amount of cloning.

Implementations§

Source§

impl<G: Debug + Default, L: Debug + Default> Reducer<G, L>

Source

pub fn new(init: G, reduce: fn(global: &mut G, local: &L)) -> Self

Creates a new reducer with a given reduction function.

The function must reduce the local value (second argument) into the global value (first argument). For the result to be deterministic, the global value must be the same regardless of the order in which the local values are reduced.

Source

pub fn share(&self) -> SharedReducer<'_, G, L>

Returns a SharedReducer referencing this Reducer.

The SharedReducer will be initialized with the default value of the base type.

Source

pub fn get(self) -> G

Consumes self and return the global value.

Note that you cannot call this method if there are still shared copies that have not been dropped.

If you just need to access the global value without consuming self, and the base type is Clone, use peek.

§Panics

This method will panic if the mutex is poisoned. peek.

Source§

impl<G: Debug + Default + Clone, L: Debug + Default> Reducer<G, L>

Source

pub fn peek(&self) -> G

Returns the current global value.

Note that this method does not guarantee that all shared copies have been dropped. If you need that guarantee, use get.

§Panics

This method will panic if the mutex is poisoned.

Trait Implementations§

Source§

impl<G: Debug + Debug + Default, L: Debug + Debug + Default> Debug for Reducer<G, L>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<G, L = G> !Freeze for Reducer<G, L>

§

impl<G, L> RefUnwindSafe for Reducer<G, L>

§

impl<G, L> Send for Reducer<G, L>
where G: Send,

§

impl<G, L> Sync for Reducer<G, L>
where G: Send,

§

impl<G, L> Unpin for Reducer<G, L>
where G: Unpin,

§

impl<G, L> UnwindSafe for Reducer<G, L>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.