1

我正在尝试创建一个HashMap使用函数式编程并利用rayon.

如果我在没有 的情况下尝试这个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 试图阻止我做一些涉及竞争条件的愚蠢的事情,但是我将如何构建一个HashMapinside apar_iter()呢?

4

1 回答 1

1

Rayon 的折叠创建中间项目(无法知道有多少)。从文档(强调我的):

平行折叠类似于顺序折叠,只是在折叠之前可以对项目的顺序进行细分。考虑一个数字列表,例如22 3 77 89 46。如果您使用顺序折叠来添加它们 ( fold(0, |a,b| a+b),您将首先添加 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的函数,而不是像标准库的空的。HashMapHashMapfold

于 2021-11-24T13:47:57.220 回答