如何使用人造丝的平行折叠创建哈希图?



我正在尝试使用函数编程和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呢?

Rayon的折叠创建了中间项目(不知道有多少(。来自文件(强调矿(:

平行折叠类似于顺序折叠,不同之处在于项目顺序可以在折叠。考虑像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

最新更新