Skip to content

Rust并行优势

Rayon 的高级并行性

Rayon 提供了多个并行迭代器适配器,可用于并行化迭代器上的常见操作,例如 、 和 。让我们看一些例子。

Parallel Map

考虑以下示例,我们要计算向量中每个元素的平方:

Rust
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let squares: Vec<_> = numbers.iter().map(|x| x * x).collect();
    println!("{:?}", squares);
}

要使用 Rayon 并行化此代码,只需使用以下方法将标准迭代器替换为并行迭代器:

Rust
use rayon::prelude::*;
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let squares: Vec<_> = numbers.par_iter().map(|x| x * x).collect();
    println!("{:?}", squares);
}

Parallel Filter

集合中的过滤元素也可以与 Rayon 并行。考虑以下示例,我们要从向量中提取偶数:

Rust
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let even_numbers: Vec<_> = numbers.iter().filter(|x| x % 2 == 0).collect();
    println!("{:?}", even_numbers);
}

要使用 Rayon 并行化此代码,请将标准迭代器替换为并行迭代器:

Rust
use rayon::prelude::*;
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let even_numbers: Vec<_> = numbers.par_iter().filter(|x| x % 2 == 0).collect();
    println!("{:?}", even_numbers);
}

Parallel Reduce

将集合减少为单个值是另一个可以从并行性中受益的常见操作。下面是计算向量中元素之和的示例:

Rust
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let sum: i32 = numbers.iter().cloned().reduce(|a, b| a + b).unwrap();
    println!("Sum: {}", sum);
}

要使用 Rayon 并行化此代码,请将标准迭代器替换为并行迭代器并使用“reduce”方法:

Rust
use rayon::prelude::*;

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let sum: i32 = numbers.par_iter().cloned().reduce(|| 0, |a, b| a + b);
    println!("Sum: {}", sum);
}

Rayon 的高级并行性

自定义并行算法

Rayon 允许您使用自定义函数创建自定义并行算法。该函数创建一个新的并行范围,同时该函数允许您在该范围内创建新的并行任务。这些任务可以共享对数据的引用,从而更轻松地处理复杂的数据结构。

以下是计算两个向量之和的简单自定义并行算法的示例:

Rust
use rayon::prelude::*;
fn main() {
    let a = vec![1, 2, 3, 4, 5];
    let b = vec![6, 7, 8, 9, 10];
    let result: Vec<_> = (0..a.len()).into_iter().collect();
    let result = &result;
    rayon::scope(|scope| {
        for (i, (ai, bi)) in a.iter().zip(b.iter()).enumerate() {
            let result = &result[i];
            scope.spawn(move |_| {
                *result.lock().unwrap() = ai + bi;
            });
        }
    });
    println!("Result: {:?}", result);
}

在此示例中,我们使用创建一个新的并行作用域。在范围内,我们迭代输入向量 和 的索引和元素。对于每对元素,我们生成一个新的并行任务,计算两个元素的总和并将结果存储在向量的相应位置。

Parallel Sort

Rayon 提供了排序算法的并行实现,可以显着加快对大量数据集合的排序速度。要使用并行排序,只需在可变切片上调用该方法即可:

Rust
use rayon::prelude::*;
fn main() {
    let mut numbers = vec![5, 4, 3, 2, 1];
    numbers.par_sort();
    println!("{:?}", numbers);
}

您还可以使用 和 方法来自定义排序行为,就像使用标准 和 方法一样。

并行连接

Rayon 的join函数允许您并行执行两个闭包并等待它们都完成。这对于将任务划分为两个可以同时执行的独立子任务非常有用。

下面是并行计算斐波那契数列的示例:

Rust
use rayon::prelude::*;
fn parallel_fibonacci(n: u32) -> u32 {
    if n <= 2 {
        1
    } else {
        let (a, b) = rayon::join(|| parallel_fibonacci(n - 1), || parallel_fibonacci(n - 2));
        a + b
    }
}
fn main() {
    let n = 20;
    let fib = parallel_fibonacci(n);
    println!("Fibonacci({}) = {}", n, fib);
}

在此示例中,我们使用 rayon::join并行计算斐波那契数。当F(n-1)和F(n-2)两个计算完成后,我们将结果相加以获得F(n) 的最终值。

Rayon 中的错误处理

错误处理是编写并发代码的一个重要方面。 Rust 的类型用于表示可能失败的计算结果。 Rayon 提供了一种在并行迭代器中处理类型的方法。

考虑以下示例,我们要计算向量中每个元素的平方根并处理潜在的错误:

Rust
use rayon::prelude::*;
fn safe_sqrt(x: f64) -> Result<f64, String> {
    if x = 0.0 {
        Ok(x.sqrt())
    } else {
        Err(format!("Cannot compute the square root of a negative number: {}", x))
    }
}
fn main() {
    let numbers = vec![1.0, 2.0, 3.0, -1.0, 4.0];
    let results: Result<Vec<_>, _> = numbers
        .par_iter()
        .map(|x| safe_sqrt(*x))
        .collect::<Vec<_>>()
        .into_iter()
        .collect();
    println!("{:?}", results);
}

在此示例中,我们使用该函数计算向量中每个元素的平方根。该函数返回一个类型,指示计算是否成功或发生错误。

我们首先使用该函数将每个数字映射到其平方根。然后,我们将结果收集到一个向量中,并将值向量转换为包含值向量的单个向量。这样,我们就可以处理并行计算期间发生的任何错误。

前端知识体系 · wcrane