# 数据并行

## 并行改变数组中元素

use rayon::prelude::*;

fn main() {
let mut arr = [0, 7, 9, 11];
arr.par_iter_mut().for_each(|p| *p -= 1);
println!("{:?}", arr);
}


## 并行测试集合中任意或所有的元素是否匹配给定断言

use rayon::prelude::*;

fn main() {
let mut vec = vec![2, 4, 6, 8];

assert!(!vec.par_iter().any(|n| (*n % 2) != 0));
assert!(vec.par_iter().all(|n| (*n % 2) == 0));
assert!(!vec.par_iter().any(|n| *n > 8 ));
assert!(vec.par_iter().all(|n| *n <= 8 ));

vec.push(9);

assert!(vec.par_iter().any(|n| (*n % 2) != 0));
assert!(!vec.par_iter().all(|n| (*n % 2) == 0));
assert!(vec.par_iter().any(|n| *n > 8 ));
assert!(!vec.par_iter().all(|n| *n <= 8 ));
}


## 使用给定断言并行搜索项

use rayon::prelude::*;

fn main() {
let v = vec![6, 2, 1, 9, 3, 8, 11];

let f1 = v.par_iter().find_any(|&&x| x == 9);
let f2 = v.par_iter().find_any(|&&x| x % 2 == 0 && x > 6);
let f3 = v.par_iter().find_any(|&&x| x > 8);

assert_eq!(f1, Some(&9));
assert_eq!(f2, Some(&8));
assert!(f3 > Some(&8));
}


## 对 vector 并行排序


use rand::distributions::Alphanumeric;
use rayon::prelude::*;

fn main() {
let mut vec = vec![String::new(); 100_000];
vec.par_iter_mut().for_each(|p| {
*p = (0..5).map(|_| rng.sample(&Alphanumeric)).collect()
});
vec.par_sort_unstable();
}


## Map-reduce 并行计算

rayon::filter 过滤集合中满足给定断言的元素。rayon::map 对每个元素执行一次计算，创建一个新的迭代；然后，基于前一次的 reduce 计算结果和当前元素一起，rayon::reduce 执行新的计算。也可以查看 rayon::sum，它与本实例中的 reduce 计算具有相同的结果。

use rayon::prelude::*;

struct Person {
age: u32,
}

fn main() {
let v: Vec<Person> = vec![
Person { age: 23 },
Person { age: 19 },
Person { age: 42 },
Person { age: 17 },
Person { age: 17 },
Person { age: 31 },
Person { age: 30 },
];

let num_over_30 = v.par_iter().filter(|&x| x.age > 30).count() as f32;
let sum_over_30 = v.par_iter()
.map(|x| x.age)
.filter(|&x| x > 30)
.reduce(|| 0, |x, y| x + y);

let alt_sum_30: u32 = v.par_iter()
.map(|x| x.age)
.filter(|&x| x > 30)
.sum();

let avg_over_30 = sum_over_30 as f32 / num_over_30;
let alt_avg_over_30 = alt_sum_30 as f32/ num_over_30;

assert!((avg_over_30 - alt_avg_over_30).abs() < std::f32::EPSILON);
println!("The average age of people older than 30 is {}", avg_over_30);
}


## 并行生成 jpg 缩略图

glob::glob_with 在当前目录中查找 jpeg 图像文件，rayon 通过 par_iter 方法调用 DynamicImage::resize，并行地调整图像大小。

use error_chain::error_chain;

use std::path::Path;
use std::fs::create_dir_all;

use error_chain::ChainedError;
use glob::{glob_with, MatchOptions};
use image::{FilterType, ImageError};
use rayon::prelude::*;

error_chain! {
Image(ImageError);
Io(std::io::Error);
Glob(glob::PatternError);
}
}

fn main() -> Result<()> {
let options: MatchOptions = Default::default();
let files: Vec<_> = glob_with("*.jpg", options)?
.filter_map(|x| x.ok())
.collect();

if files.len() == 0 {
error_chain::bail!("No .jpg files found in current directory");
}

let thumb_dir = "thumbnails";
create_dir_all(thumb_dir)?;

println!("Saving {} thumbnails into '{}'...", files.len(), thumb_dir);

let image_failures: Vec<_> = files
.par_iter()
.map(|path| {
make_thumbnail(path, thumb_dir, 300)
.map_err(|e| e.chain_err(|| path.display().to_string()))
})
.filter_map(|x| x.err())
.collect();

image_failures.iter().for_each(|x| println!("{}", x.display_chain()));

println!("{} thumbnails saved successfully", files.len() - image_failures.len());
Ok(())
}

fn make_thumbnail<PA, PB>(original: PA, thumb_dir: PB, longest_edge: u32) -> Result<()>
where
PA: AsRef<Path>,
PB: AsRef<Path>,
{
let img = image::open(original.as_ref())?;
let file_path = thumb_dir.as_ref().join(original);

Ok(img.resize(longest_edge, longest_edge, FilterType::Nearest)
.save(file_path)?)
}