简介
欢迎来到「使用 Send 和 Sync 特性实现可扩展并发」实验。本实验是 Rust 程序设计语言 的一部分。你可以在 LabEx 中练习 Rust 技能。
在本实验中,我们将探索 Rust 中的两个并发概念——Send
和 Sync
特性,它们提供了超越标准库的可扩展并发能力。
This tutorial is from open-source community. Access the source code
💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版
欢迎来到「使用 Send 和 Sync 特性实现可扩展并发」实验。本实验是 Rust 程序设计语言 的一部分。你可以在 LabEx 中练习 Rust 技能。
在本实验中,我们将探索 Rust 中的两个并发概念——Send
和 Sync
特性,它们提供了超越标准库的可扩展并发能力。
有趣的是,Rust 语言本身的并发特性非常少。到目前为止,我们在本章中讨论的几乎每个并发特性都是标准库的一部分,而不是语言本身的特性。你处理并发的选项不限于语言或标准库;你可以编写自己的并发特性,或者使用其他人编写的特性。
然而,语言中嵌入了两个并发概念:std::marker
特性 Send
和 Sync
。
Send
标记特性表明,实现了 Send
的类型的值的所有权可以在线程间转移。几乎所有的 Rust 类型都是 Send
,但也有一些例外,包括 Rc<T>
:它不能是 Send
,因为如果你克隆一个 Rc<T>
值并试图将克隆的所有权转移到另一个线程,两个线程可能会同时更新引用计数。因此,Rc<T>
用于不需要承担线程安全性能开销的单线程场景。
因此,Rust 的类型系统和 trait 边界确保你永远不会意外地在线程间不安全地发送 Rc<T>
值。当我们在清单 16-14 中尝试这样做时,我们得到了错误 the trait
Sendis not implemented for
Rc<Mutex}
。当我们切换到 Arc<T>
(它是 Send
)时,代码编译通过。
任何完全由 Send
类型组成的类型也会自动被标记为 Send
。除了原始指针(我们将在第 19 章讨论)之外,几乎所有的原始类型都是 Send
。
Sync
标记特性表明,对于实现了 Sync
的类型,从多个线程引用它是安全的。换句话说,如果 &T
(对 T
的不可变引用)是 Send
,则任何类型 T
就是 Sync
,这意味着该引用可以安全地发送到另一个线程。与 Send
类似,原始类型是 Sync
,并且完全由 Sync
类型组成的类型也是 Sync
。
智能指针 Rc<T>
由于与它不是 Send
相同的原因,也不是 Sync
。RefCell<T>
类型(我们在第 15 章讨论过)以及相关的 Cell<T>
类型家族都不是 Sync
。RefCell<T>
在运行时进行的借用检查实现不是线程安全的。智能指针 Mutex<T>
是 Sync
,并且正如你在“在多个线程之间共享 Mutex<T>
”中看到的,可以用于与多个线程共享访问。
由于由 Send
和 Sync
特性组成的类型会自动也是 Send
和 Sync
,所以我们不必手动实现这些特性。作为标记特性,它们甚至没有任何方法需要实现。它们只是有助于强制实施与并发相关的不变性。
手动实现这些特性涉及编写不安全的 Rust 代码。我们将在第 19 章讨论使用不安全的 Rust 代码;目前,重要的信息是,构建不由 Send
和 Sync
部分组成的新并发类型需要仔细考虑以维护安全保证。位于 https://doc.rust-lang.org/stable/nomicon 的《Rustonomicon》有关于这些保证以及如何维护它们的更多信息。
恭喜你!你已经完成了“使用 Send 和 Sync 特性实现可扩展并发”实验。你可以在 LabEx 中练习更多实验来提升你的技能。