Rust心得 - 202510
Rust心得 - 202510
Fn trait 家族
// 不可变借用的闭包 - 可以并发调用
Fn(&self) -> Output
// 可变借用的闭包 - 不能安全并发
FnMut(&mut self) -> Output
// 获取所有权的闭包 - 只能调用一次
FnOnce(self) -> OutputSend + Sync trait
对于真正的并发,还需要:
// 可以安全地在线程间传递所有权
T: Send
// 可以安全地在线程间共享不可变引用
T: Sync吐槽
类型吐槽
对于复合类型的参数和返回值,ts 是最爽的,c enum 稍不爽,rust enum 很不爽
Arc 原理
rust 的 Arc:: 变量,是通过锁实现的吗?还是什么?性能如何
你好!这是一个非常好的问题,直击 Rust 并发编程的核心。
简单来说:Arc 不是通过锁实现的,而是通过原子操作(Atomic Operations)实现的。
下面详细解释一下:
1. Arc 是什么?如何工作?
Arc 的全称是 Atomically Reference Counted(原子引用计数)。它是一个智能指针,允许多个线程以安全的方式“共享”同一份数据的所有权。
- 核心机制:引用计数
Arc内部包含一个指向堆上数据的指针,以及一个“引用计数器”。- 当你克隆(
clone)一个Arc时,它不会复制底层的数据,而仅仅是原子性地将引用计数加一。 - 当一个
Arc的实例离开作用域(被drop)时,它会原子性地将引用计数减一。 - 只有当引用计数变为 0 时,底层的数据才会被真正地释放。
- 当你克隆(
- 关键点:原子操作
这里的“原子性”是关键。在多线程环境中,多个线程可能同时尝试增加或减少引用计数。如果使用普通的加减法,会导致数据竞争(Data Race),最终计数会出错。Arc使用的是 CPU 提供的原子指令(例如fetchadd,fetchsub)。这些指令是不可中断的,能确保即使在多核 CPU 上,计数的修改也是完整、独立的,从而保证了线程安全。
2. Arc 和锁(Mutex)的区别
这是最容易混淆的地方:
Arc:保证“共享所有权”的线程安全。
它只保证引用计数本身在多线程下的正确性。它不提供对内部数据的修改(mutability)能力。你不能直接通过一个Arc<T>来修改T。- 锁 (
Mutex,RwLock):保证“数据访问”的线程安全。
锁提供的是“互斥”(Mutual Exclusion)。当你想要修改数据时,必须先获取锁。一旦一个线程获得了锁,其他线程就必须等待,直到该锁被释放。这保证了在任何时刻,只有一个线程能访问或修改数据。
3. Arc 和 Mutex 的结合使用
在实际的并发编程中,我们常常需要既能在线程间共享数据,又能修改它。因此,Arc<Mutex<T>> 这个组合非常常见:
Arc<T>:让多个线程都能“拥有”指向T的指针。Mutex<T>:包裹住数据T,提供一个安全的修改机制。
当你这样做时:
- 使用
Arc::clone()将Arc<Mutex<T>>的所有权安全地分发给多个线程。这个过程是无锁的,只涉及原子操作。 - 在某个线程中,当你需要访问或修改内部数据
T时,你必须调用.lock()方法来获取Mutex的锁。这个过程是阻塞的,可能会产生等待。
所以,锁的开销来自于 Mutex,而不是 Arc。
4. 性能如何?
Arc本身的性能非常好- 克隆
Arc和销毁它只涉及一次原子操作。在现代 CPU 上,原子操作是一条硬件指令,速度非常快,远比操作系统层面的锁(获取和释放)要轻量。 - 与单线程的
Rc(非原子引用计数)相比,Arc会有一点点性能开销,因为原子操作需要处理 CPU 缓存同步等问题,比普通整数加减要慢一些。但在绝大多数情况下,这点开销是完全可以接受的,并且是线程安全所必需的。
- 克隆
- 瓶颈通常在锁上
如果你的程序中大量使用了Arc<Mutex<T>>,性能瓶颈几乎总是出现在对Mutex的争用上。如果多个线程频繁地需要获取同一个锁,就会导致大量的等待,从而降低程序的并发性能。
总结
| 特性 | Arc | Mutex |
|---|---|---|
| 目的 | 在线程间安全地共享数据所有权 | 保护数据,提供安全的独占访问/修改 |
| 实现机制 | 原子引用计数 (Atomic Operations) | 操作系统提供的锁机制 (如 futex) |
| 是否加锁 | 否 | 是 |
| 性能开销 | 低 (一次原子指令) | 高 (可能涉及系统调用和线程阻塞) |
再看 rust match
用久了对 match 有了更深层次的体会,一句话总结:
ts 的 if 允许类型缩窄,而 rust 的 if 不允许类型缩窄。rust 的 match 就是带类型缩窄的 if 语句
链接到当前文件 0
没有文件链接到当前文件