不能使用 Rayon 的 `.par_iter()`

Cannot use Rayon's `.par_iter()`

我有一个实现 Iterator 的结构,它作为迭代器工作正常。它生成值,并使用 .map(),我从本地 HTTP 服务器下载每个项目并保存结果。我现在想并行化这个操作,Rayon 看起来很友好。

我在尝试按照文档中的示例操作时遇到编译器错误。

这是按顺序工作的代码。 generate_values returns 实现 Iterator 的结构。 dl 下载值并保存它们(即它有副作用)。由于迭代器在 Rust 中是惰性的,我在最后放了一个 .count() 这样它实际上会 运行 它。

generate_values(14).map(|x| { dl(x, &path, &upstream_url); }).count();

按照人造丝的例子,我尝试了这个:

generate_values(14).par_iter().map(|x| { dl(x, &path, &upstream_url); }).count();

并出现以下错误:

src/main.rs:69:27: 69:37 error: no method named `par_iter` found for type `MyIterator` in the current scope

有趣的是,当我使用 .iter() 时,许多 Rust 东西都使用了它,我得到了类似的错误:

src/main.rs:69:27: 69:33 error: no method named `iter` found for type `MyIterator` in the current scope
src/main.rs:69     generate_values(14).iter().map(|tile| { dl_tile(tile, &tc_path, &upstream_url); }).count();

既然我实施了Iterator,我应该免费获得.iter()吧?这就是 .par_iter() 不起作用的原因吗?

Rust 1.6 和人造丝 0.3.1

$ rustc --version
rustc 1.6.0 (c30b771ad 2016-01-19)

不,Iterator 特性与 iter() 方法无关。是的,这有点令人困惑。

这里有几个不同的概念。一个Iterator是可以吐值的类型;它只需要实现 next() 并且还有许多其他方法,但是其中 none 是 iter()。然后是 IntoIterator 表示类型可以转换为 Iterator。此特征具有 into_iter() 方法。现在 iter() 方法与这两个特征中的任何一个都不 真正 相关。它只是许多类型的普通方法,通常类似于 into_iter().

现在解决你的 Rayon 问题:看起来你不能只使用任何普通迭代器并将其变成并行迭代器。但是,我从未使用过这个库,所以对此持保留态度。在我看来,您需要将迭代器收集到 Vec 中才能使用 par_iter().

注意:使用普通迭代器时,不应使用 map()count(),而应使用标准 for 循环。

Rayon 0.3.1 将 par_iter 定义为:

pub trait IntoParallelRefIterator<'data> {
    type Iter: ParallelIterator<Item=&'data Self::Item>;
    type Item: Sync + 'data;

    fn par_iter(&'data self) -> Self::Iter;
}

只有one type that implements this trait in Rayon itself: [T]:

impl<'data, T: Sync + 'data> IntoParallelRefIterator<'data> for [T] {
    type Item = T;
    type Iter = SliceIter<'data, T>;

    fn par_iter(&'data self) -> Self::Iter {
        self.into_par_iter()
    }
}

这就是为什么 collectVec 会起作用的原因; Vec 取消对切片的引用。

通常,Rayon 无法假定 any 迭代器可以并行化,因此它不能默认包含所有 Iterator

既然你已经定义了 generate_values,你也可以为它实现适当的 Rayon 特性:

  1. IntoParallelIterator
  2. IntoParallelRefIterator
  3. IntoParallelRefMutIterator

这应该可以让您避免收集到临时向量中。