Rust

2025年10月17日更新 9 人订阅
原价: ¥ 6 限时优惠
专栏简介 Rust编程语言之错误处理 Rust 语言之 flod Rust编程语言之Cargo、Crates.io详解 Rust编程语言之枚举与模式匹配 Rust语言 - 接口设计的建议之受约束(Constrained) Rust编程语言之无畏并发 Rust语言 - 接口设计的建议之灵活(flexible) Rust语言 - 接口设计的建议之显而易见(Obvious) Rust语言 - 接口设计的建议之不意外(unsurprising) Rust 实战:构建实用的 CLI 工具 HTTPie Rust编程语言学习之高级特性 Rust内存管理揭秘:深度剖析指针与智能指针 解决Rust中数组和切片的编译时大小问题 《Rust编程之道》学习笔记一 Rust Async 异步编程 简易教程 使用 Async Rust 构建简单的 P2P 节点 Rust编程语言入门之模式匹配 Rust async 编程 Rust编程语言之编写自动化测试 Rust编程语言之函数式语言特性:迭代器和闭包 《Rust编程之道》学习笔记二 Rust Tips 比较数值 使用 Rust 开发一个微型游戏 Rust编程初探:深入理解Struct结构体 深入理解Rust中的内存管理:栈、堆与静态内存详解 深入理解 Rust 结构体:经典结构体、元组结构体和单元结构体的实现 深入掌握 Rust 结构体:从模板到实例化的完整指南 深入理解Rust中的结构体:逻辑与数据结合的实战示例 深入理解 Rust 枚举:从基础到实践 掌握Rust字符串的精髓:String与&str的最佳实践 全面解析 Rust 模块系统:实战案例与应用技巧 Rust 中的 HashMap 实战指南:理解与优化技巧 掌握Rust模式匹配:从基础语法到实际应用 Rust 中的面向对象编程:特性与实现指南 深入理解 Rust 的 Pin 和 Unpin:理论与实践解析 Rust Trait 与 Go Interface:从设计到实战的深度对比 从零开始:用 Rust 和 Axum 打造高效 Web 应用 Rust 错误处理详解:掌握 anyhow、thiserror 和 snafu Rust 如何优雅实现冒泡排序 链表倒数 K 节点怎么删?Python/Go/Rust 实战 用 Rust 玩转数据存储:JSON 文件持久化实战 Rust实战:打造高效字符串分割函数 如何高效学习一门技术:从知到行的飞轮效应 Rust 编程入门:Struct 让代码更优雅 Rust 编程:零基础入门高性能开发 用 Rust 写个猜数游戏,编程小白也能上手! Rust 入门教程:变量到数据类型,轻松掌握! 深入浅出 Rust:函数、控制流与所有权核心特性解析 从零开始:用 Rust 和 Axum 打造高效 Web 服务 Rust 集合类型解析:Vector、String、HashMap 深入浅出Rust:泛型、Trait与生命周期的硬核指南 Rust实战:博物馆门票限流系统设计与实现 用 Rust 打造高性能图片处理服务器:从零开始实现类似 Thumbor 的功能 Rust 编程入门实战:从零开始抓取网页并转换为 Markdown 深入浅出 Rust:高效处理二进制数据的 Bytes 与 BytesMut 实战 Rust智能指针:解锁内存管理的进阶之道 用 Rust 打造命令行利器:从零到一实现 mini-grep 解锁Rust代码组织:轻松掌握Package、Crate与Module Rust 所有权:从内存管理到生产力释放 深入解析 Rust 的面向对象编程:特性、实现与设计模式 Rust + Protobuf:从零打造高效键值存储项目 bacon 点燃 Rust:比 cargo-watch 更爽的开发体验 用 Rust 打造微型游戏:从零开始的 Flappy Dragon 开发之旅 函数式编程的Rust之旅:闭包与迭代器的深入解析与实践 探索Rust编程之道:从设计哲学到内存安全的学习笔记 精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用 Rust 避坑指南:搞定数值比较,别再让 0.1 + 0.2 != 0.3 困扰你! 告别 Vec!掌握 Rust bytes 库,解锁零拷贝的真正威力 告别竞态条件:基于 Axum 和 Serde 的 Rust 并发状态管理最佳实践 Rust 异步编程实践:从 Tokio 基础到阻塞任务处理模式 Rust 网络编程实战:用 Tokio 手写一个迷你 TCP 反向代理 (minginx) 保姆级教程:Zsh + Oh My Zsh 终极配置,让你的 Ubuntu 终端效率倍增 不止于后端:Rust 在 Web 开发中的崛起之路 (2024数据解读) Rust核心利器:枚举(Enum)与模式匹配(Match),告别空指针,写出优雅健壮的代码 Rust 错误处理终极指南:从 panic! 到 Result 的优雅之道 想用 Rust 开发游戏?这份超详细的入门教程请收好! 用 Rust 实现 HTTPie:一个现代 CLI 工具的构建过程 Rust 异步实战:从0到1,用 Tokio 打造一个高性能并发聊天室 深入 Rust 核心:彻底搞懂指针、引用与智能指针 Rust 生产级后端实战:用 Axum + sqlx 打造高性能短链接服务 深入 Rust 内存模型:栈、堆、所有权与底层原理 Rust 核心概念解析:引用、借用与内部可变性 掌握 Rust 核心:生命周期与借用检查全解析 Rust 内存布局深度解析:从对齐、填充到 repr 属性 Rust Trait 分派机制:静态与动态的抉择与权衡 Rust Thread::Builder 用法详解:线程命名与栈大小设置 Rust 泛型 Trait:关联类型与泛型参数的核心区别 Rust Scoped Threads 实战:更安全、更简洁的并发编程 Rust 核心设计:孤儿规则与代码一致性解析 Rust 实战:从零构建一个多线程 Web 服务器 Rust Web 开发实战:构建教师管理 API 硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端 Rust Web 开发实战:使用 SQLx 连接 PostgreSQL 数据库 硬核入门:从零开始,用 Actix Web 构建你的第一个 Rust REST API (推荐 🔥) Rust 并发编程:详解线程间数据共享的几种核心方法 Rust并发安全基石:Mutex与RwLock深度解析 Rust Web实战:构建优雅的 Actix Web 统一错误处理 煮咖啡里的大学问:用 Rust Async/Await 告诉你如何边烧水边磨豆 深入浅出:Rust 原子类型与多线程编程实践 Rust 并发编程利器:OnceCell 与 OnceLock 深度解析 Rust 懒人编程:LazyCell 与 LazyLock 的惰性哲学 Rust 入门精髓:详解 Enum 的三种魔法,从模式匹配到状态管理 Rust 字符串魔法:String 与 &str 的深度解析与实践 Rust 模块化编程:驾驭代码结构与可见性的三大法则 Rust 实用进阶:深度剖析 Rust 生命周期的奥秘 Rust 智能指针大揭秘:Box、Rc、Arc、Cow 深度剖析与应用实践 Rust 并发编程三步曲:Join、Arc<Mutex> 与 mpsc 通道同步实战 Rust 声明宏实战进阶:从基础定义到 #[macro_export] 与多规则重载 Rust 类型转换实战:利用 From/Into Trait 实现带 Default 容错的安全转换 Rust 实战:实现 FromStr Trait,定制化字符串 parse() 与精确错误报告 Rust 实战:TryFrom Trait——如何在类型转换中强制执行业务逻辑检查 Rust 泛型编程基石:AsRef 和 AsMut 的核心作用与实战应用 揭秘 Rust Unsafe 编程:程序员接管内存安全的契约与实践 Rust FFI 入门:extern、ABI 与底层符号链接解析 Rust性能优化:零内存拷贝的链表合并技术实战 Rust 进阶:用 NonNull 裸指针实现高性能双向链表 O(N) 反转实战 Rust实战:如何用泛型和特性实现一个高性能、通用的插入排序 Rust实战:深度解析二叉搜索树(BST)的实现,掌握泛型与内存安全 用 Rust 优雅实现图搜索核心算法:广度优先搜索 (BFS) 实战 Rust 多线程的高效等待术:park() 与 unpark() 信号通信实战 Rust 并发加速器:用 Condvar 实现线程间“精确握手”与高效等待 Rust 算法精讲:用 DFS 玩转图遍历,从起点“一走到底”的秘密 Rust 并发实战:用 MPSC 通道构建线程安全的“任务指挥中心” 一行代码提速 30 倍!Rust Rayon 并行计算:告别多线程管理困境

一行代码提速 30 倍!Rust Rayon 并行计算:告别多线程管理困境

一行代码提速30倍!RustRayon并行计算:告别多线程管理困境在高性能计算领域,多核CPU的潜力常常被传统顺序代码所限制。我们渴望并行加速,但又惧怕手动管理线程、锁和数据竞争带来的复杂性与风险。Rust语言以其安全性和性能著称,而Rayon库则是Rust生态中解决数据并行

一行代码提速 30 倍!Rust Rayon 并行计算:告别多线程管理困境

在高性能计算领域,多核 CPU 的潜力常常被传统顺序代码所限制。我们渴望并行加速,但又惧怕手动管理线程、锁和数据竞争带来的复杂性与风险。Rust 语言以其安全性和性能著称,而 Rayon 库则是 Rust 生态中解决数据并行化问题的"银弹"。它承诺:用近乎零成本的语法切换,即可将顺序迭代器华丽地升级为并行计算,且完全继承 Rust 的数据竞争安全保证。 本文将通过两个实战案例——百万级数据求和与高效质数查找,展示 Rayon 如何让你真正专注于业务逻辑,将繁重的并行任务安全、高效地交给它处理。

Rust 多线程 - Rayon crate

Rayon 简介

Rayon 是用于 Rust 的数据并行库

主要特点

  • 极其轻量,并且可以轻松地将顺序计算转换为并行计算
  • 可以保证数据竞争(Data race)的安全性

实操

创建项目

cargo new rayon_iters
cd rayon_iters
ls
cc # open -a cursor .
cargo add rayon         

示例一

use rayon::prelude::*;
fn main() {
    let nums: Vec&lt;u64> = (0..1000000).collect();
    let sum: u64 = nums.par_iter().sum::&lt;u64>();
    println!("Sum: {sum}");
}

Rayon 会自动创建一个线程池,每个CPU就是一个线程。并且还会使用一个任务队列,这个队列实现了工作窃取机制,这个机制是避免线程空闲,同时还支持子任务 sub task,就是一个任务可以等待另一个任务的完成。

  • par_iter 用于不可变引用的并行迭代

  • par_iter_mut 用于可变引用的并行迭代

  • into_par_iter 用于所有权的并行迭代

Rust 并行计算:

用 Rayon 实现百万级数据的高效求和

这段代码的核心目标是:创建一个包含一百万个数字的向量,并利用 Rust 的 Rayon 库,以最简洁的方式在多个 CPU 核心上并行计算这些数字的总和。

代码解析

1. 引入与初始化

use rayon::prelude::*;
fn main() {
    // ...
}
  • *`use rayon::prelude::;**: 这是使用 Rayon 并行的关键。它导入了ParallelIteratortrait,允许您在集合类型(如Vec)上调用以par_开头的方法(如par_iter()`)。
  • let nums: Vec&lt;u64> = (0..1000000).collect();:
    • 创建一个名为 nums 的向量。
    • 它包含从 0 到 999,999 的一百万个 64 位无符号整数(u64)。
    • 为了体现并行的优势,我们通常需要处理较大的数据集,这里的一百万个数字提供了理想的测试场景。

2. 并行计算核心

let sum: u64 = nums.par_iter().sum::&lt;u64>();

这是整个代码中最强大的一行,它将顺序计算变成了并行计算:

  • nums.par_iter(): 这一步是 Rayon 魔法的起点。它将 Rust 标准库的顺序迭代器 (iter()) 转换成一个 并行迭代器
    • Rayon 会智能地将这个一百万个元素的向量自动切分成多个块(通常数量等于您的 CPU 核心数)。
    • 这些块会被分配给 Rayon 的内部工作线程池。
  • .sum::&lt;u64>(): 这是一个归约(Reduction)操作。
    • 每个工作线程独立地计算分配给它的那个数据块的部分和
    • Rayon 负责在所有线程完成计算后,安全且高效地将所有部分和合并成最终的 sum 结果。

3. 输出结果

println!("Sum: {sum}");
  • 打印出最终计算得到的总和。由于 Rayon 保证了线程安全和结果的正确合并,这个结果与顺序计算的结果完全一致。

Rayon 的优势:数据并行性

这段代码的亮点在于,它展示了 Rayon 如何实现数据并行性 (Data Parallelism),即在多个处理器上同时对数据的不同部分执行相同的操作(本例中是求和)。

  1. 极简的语法切换:nums.iter().sum() 切换到 nums.par_iter().sum() 几乎零成本,无需手动管理线程、锁或互斥量。
  2. 自动负载均衡: Rayon 的工作窃取(Work-Stealing)调度器会自动将工作负载均匀地分配给所有可用线程,最大化 CPU 利用率。
  3. 安全保证: 由于 Rayon 是基于 Rust 的所有权和生命周期系统构建的,它从根本上消除了数据竞争,保证了并行操作的安全性。

简而言之,这段代码是一个教科书式的例子,说明了在 Rust 中利用 Rayon 库,可以轻松、安全地将计算密集型任务并行化,从而显著提高执行速度。

运行

➜ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/rayon_iters`
Sum: 499999500000

这段运行结果有力地证明了 Rayon 并行计算的高效性准确性。输出的 Sum: 499999500000 是从0到999,999的所有整数之和的精确理论值,这表明 Rayon 成功地将一百万个数字的向量切分给多个 CPU 核心,让它们独立计算部分和,并最终安全、无误地将这些部分结果合并(归约) 成了正确的最终总和。同时,Finished 语句中极短的耗时,也暗示了 Rayon 在处理这类计算密集型任务时,所展现出的出色并行加速能力。

示例二

use std::time::Instant;

use rayon::prelude::*;

fn is_prime(n: u32) -> bool {
    (2..=n / 2).into_par_iter().all(|i| n % i != 0)
}

fn main() {
    let now = Instant::now();
    let nums: Vec&lt;u64> = (2..1000000).collect();
    let mut primes: Vec&lt;&u64> = nums.par_iter().filter(|&n| is_prime(*n as u32)).collect();
    let elapsed = now.elapsed();

    primes.par_sort_unstable();

    println!("{primes:?}");
    println!("{} ms to find {} primes", elapsed.as_millis(), primes.len());
}

这段 Rust 代码是 Rayon 在双重并行计算中应用的一个高级示例,它用于高效地找出一百万以内(从 2 到 999,999)的所有质数,并精确测量性能。程序的核心是 is_prime 函数,它利用 into_par_iter().all()质数判断过程本身并行化:检查一个数 n 是否为质数时,对其除数范围 $$ (2...n/2) $$ 的遍历和取模检查是并发进行的。在 main 函数中,主逻辑通过 nums.par_iter().filter() 将对百万个数字的筛选也并行化,这意味着一百万次独立的、且自身也是并行的质数检查都在 Rayon 线程池上同时进行,实现了最大化的 CPU 利用率。代码使用 std::time::Instant 精确测量了从开始筛选到收集结果的总耗时,最终通过 println! 语句打印出找到的质数列表、总数量和运行时间,有力地证明了 Rayon 在这种计算密集型任务中带来的显著性能提升。

运行

在 Rust 项目中,cargo run 命令的作用是:

  1. 编译 (Compile): 自动编译您的项目源代码(如果自上次运行以来代码有更改)。

  2. 运行 (Run): 执行编译成功后生成的二进制可执行文件。

    
    ➜ cargo run
    ... ...
    99091, 999101, 999133, 999149, 999169, 999181, 999199, 999217, 999221, 999233, 999239, 999269, 999287, 999307, 999329, 999331, 999359, 999371, 999377, 999389, 999431, 999433, 999437, 999451, 999491, 999499, 999521, 999529, 999541, 999553, 999563, 999599, 999611, 999613, 999623, 999631, 999653, 999667, 999671, 999683, 999721, 999727, 999749, 999763, 999769, 999773, 999809, 999853, 999863, 999883, 999907, 999917, 999931, 999953, 999959, 999961, 999979, 999983]
    47750 ms to find 78498 primes

➜ cargo run --release ... ... 998813, 998819, 998831, 998839, 998843, 998857, 998861, 998897, 998909, 998917, 998927, 998941, 998947, 998951, 998957, 998969, 998983, 998989, 999007, 999023, 999029, 999043, 999049, 999067, 999083, 999091, 999101, 999133, 999149, 999169, 999181, 999199, 999217, 999221, 999233, 999239, 999269, 999287, 999307, 999329, 999331, 999359, 999371, 999377, 999389, 999431, 999433, 999437, 999451, 999491, 999499, 999521, 999529, 999541, 999553, 999563, 999599, 999611, 999613, 999623, 999631, 999653, 999667, 999671, 999683, 999721, 999727, 999749, 999763, 999769, 999773, 999809, 999853, 999863, 999883, 999907, 999917, 999931, 999953, 999959, 999961, 999979, 999983] 1552 ms to find 78498 primes



这段运行输出展示了使用 **Rust Rayon 库**在不同编译模式下执行百万以内质数查找任务(一个计算密集型任务)的性能对比和结果的准确性。

### 运行结果详细解释

1. **结果的准确性与一致性:**

   - 两次运行都成功找到了 **78,498 个质数**(`to find 78498 primes`)。
   - 输出的质数列表(部分可见)在两次运行中也是一致的。
   - 这证明了您的 Rayon 并行算法(很可能采用了嵌套的并行迭代,即并行查找和并行质数判断)是**线程安全且正确的**,无论在哪个线程上执行,结果都具有确定性。

2. **Debug 与 Release 模式的性能天壤之别(核心发现):**

   - **Debug 模式 (`cargo run`) 耗时:** 47,750 ms(约 47.75 秒)。
   - **Release 模式 (`cargo run --release`) 耗时**:1,552 ms (约 1.55 秒)。

   这个巨大的差异(快了约 **30 倍**)是 Rust 编译器的典型表现:

   - **Debug 模式**编译速度快,但**关闭了所有优化**,代码执行效率极低。
   - **Release 模式**花费更长的编译时间,但会进行极致的优化(如内联、循环展开等),因此执行速度极快。对于计算密集型任务,**并行化 (Rayon) 只有在 Release 优化下才能真正发挥出极致性能。**

**总结:**

这段结果完美地验证了两个关键点:您的 Rayon 代码是**正确且线程安全的**(两次运行结果一致),并且通过 Rust 编译器配合 Rayon 的并行能力,成功地将一个需要近一分钟的计算任务**加速到了仅需 1.5 秒左右**,展示了 Rust 在高性能计算方面的巨大优势。

## 总结

Rayon 库完美地践行了 Rust 在安全和性能上的双重承诺。通过本文的两个实战案例——百万级求和与复杂质数筛选——我们深刻体会到 Rayon 的核心价值:

1. **极简的并行化**:从 `iter()` 到 `par_iter()` 的**几乎零成本切换**,让并行编程变得触手可及。
2. **内置的安全性**:Rayon 的设计基于 Rust 的所有权系统,**从根本上杜绝了多线程编程中常见的数据竞争**,让开发者可以安心地享受并行带来的性能提升。
3. **极致的性能**:得益于其智能的**工作窃取(Work-Stealing)调度器**,Rayon 能最大限度地利用所有 CPU 核心,并在 Release 模式的优化下,为计算密集型任务带来**数十倍的性能加速**。

对于任何希望在 Rust 中处理大数据集或计算密集型任务的开发者而言,Rayon 都是一个不可或缺的高性能工具。它让高性能不再意味着高风险和高复杂度。

## 参考

- https://github.com/rayon-rs/rayon
- https://docs.rs/rayon/latest/rayon/
- https://rustcc.cn/article?id=181e0a73-6742-42a9-b7a1-1c00bef436c2
- https://www.reddit.com/r/rust/comments/1348njv/is_rayon_always_worth_it/
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论