我正在尝试使用函数编程和rayon
的并行化来创建HashMap
。
如果我在没有rayon
的情况下尝试,它会起作用:
use std::collections::HashMap;
fn main() {
let nums = [1, 2, 1, 2, 1, 2];
let result: HashMap<i32, i32> =
nums.iter()
.filter(|x| *x % 2 == 0)
.fold(HashMap::new(), |mut acc, x| {
*acc.entry(*x).or_insert(0) += 1;
acc
});
println!("{:?}", result);
}
如果我试图通过从iter()
切换到par_iter()
来使用多个核心,我会得到一个错误:
use rayon::prelude::*; // 1.5.1
use std::collections::HashMap;
fn main() {
let nums = [1, 2, 1, 2, 1, 2];
let result: HashMap<i32, i32> =
nums.par_iter()
.filter(|x| *x % 2 == 0)
.fold(HashMap::new(), |mut acc, x| {
*acc.entry(*x).or_insert(0) += 1;
acc
});
println!("{:?}", result);
}
error[E0277]: expected a `Fn<()>` closure, found `HashMap<_, _>`
--> src/main.rs:9:19
|
9 | .fold(HashMap::new(), |mut acc, x| {
| ^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `HashMap<_, _>`
|
= help: the trait `Fn<()>` is not implemented for `HashMap<_, _>`
= note: wrap the `HashMap<_, _>` in a closure with no arguments: `|| { /* code */ }`
error[E0308]: mismatched types
--> src/main.rs:7:9
|
6 | let result: HashMap<i32, i32> =
| ----------------- expected due to this
7 | / nums.par_iter()
8 | | .filter(|x| *x % 2 == 0)
9 | | .fold(HashMap::new(), |mut acc, x| {
10 | | *acc.entry(*x).or_insert(0) += 1;
11 | | acc
12 | | });
| |______________^ expected struct `HashMap`, found struct `Fold`
|
= note: expected struct `HashMap<i32, i32>`
found struct `Fold<rayon::iter::Filter<rayon::slice::Iter<'_, {integer}>, [closure@src/main.rs:8:21: 8:36]>, HashMap<_, _>, _>`
显然,Rust试图阻止我做一些涉及种族条件的愚蠢事情,但我该如何在par_iter()
中构建HashMap
呢?
平行折叠类似于顺序折叠,不同之处在于项目顺序可以在折叠。考虑像
22 3 77 89 46
这样的数字列表。如果使用顺序折叠将它们相加(CCD_ 9,你会先加0+22,然后加22+3,再加25+77等等除了它首先将您的列表分解为子列表,因此它没有在最后产生一个和,而是产生了多次求和。结果的数量是不确定的,因为是发生断裂的点
您需要将这些中间项目减少为最终项目:
use rayon::prelude::*; // 1.5.1
use std::collections::HashMap;
fn main() {
let nums = [1, 2, 1, 2, 1, 2];
let result: HashMap<i32, i32> = nums
.par_iter()
.filter(|x| *x % 2 == 0)
.fold(HashMap::new, |mut acc, x| {
*acc.entry(*x).or_insert(0) += 1;
acc
})
.reduce_with(|mut m1, m2| {
for (k, v) in m2 {
*m1.entry(k).or_default() += v;
}
m1
})
.unwrap();
println!("{:?}", result);
}
游乐场
还要注意,Rayon的fold
的第一个参数是创建空HashMap
的函数,而不是像标准库的fold
那样的空HashMap
。