Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

使用 SendSync 实现可扩展并发

Extensible Concurrency with Send and Sync

有趣的是,本章到目前为止讨论的几乎每一个并发特性都是标准库的一部分,而不是语言本身。你处理并发的选择并不局限于语言或标准库;你可以编写自己的并发特性或使用他人编写的特性。

Interestingly, almost every concurrency feature we’ve talked about so far in this chapter has been part of the standard library, not the language. Your options for handling concurrency are not limited to the language or the standard library; you can write your own concurrency features or use those written by others.

然而,在嵌入语言本身而非标准库的关键并发概念中,包括 std::marker trait 中的 SendSync

However, among the key concurrency concepts that are embedded in the language rather than the standard library are the std::marker traits Send and Sync.

使用 Send 在线程间转移所有权

Transferring Ownership Between Threads

Send 标记 trait 表明实现了 Send 的类型的所有权可以在线程之间转移。几乎所有的 Rust 类型都实现了 Send,但也有一些例外,包括 Rc<T>:它不能实现 Send,因为如果你克隆了一个 Rc<T> 值并尝试将克隆的所有权转移到另一个线程,两个线程可能会同时更新引用计数。出于这个原因,Rc<T> 被实现为在单线程情况下使用,因为在那里你不想承担线程安全的性能开销。

The Send marker trait indicates that ownership of values of the type implementing Send can be transferred between threads. Almost every Rust type implements Send, but there are some exceptions, including Rc<T>: This cannot implement Send because if you cloned an Rc<T> value and tried to transfer ownership of the clone to another thread, both threads might update the reference count at the same time. For this reason, Rc<T> is implemented for use in single-threaded situations where you don’t want to pay the thread-safe performance penalty.

因此,Rust 的类型系统和 trait bound 确保了你永远不会意外地在线程间不安全地发送 Rc<T> 值。当我们在示例 16-14 中尝试这样做时,得到了错误 the trait `Send` is not implemented for `Rc<Mutex<i32>>`。当我们切换到实现了 SendArc<T> 时,代码便编译通过了。

Therefore, Rust’s type system and trait bounds ensure that you can never accidentally send an Rc<T> value across threads unsafely. When we tried to do this in Listing 16-14, we got the error the trait `Send` is not implemented for `Rc<Mutex<i32>>`. When we switched to Arc<T>, which does implement Send, the code compiled.

任何完全由 Send 类型组成的类型也会被自动标记为 Send。除了裸指针(我们将在第 20 章讨论)之外,几乎所有的原始类型都是 Send

Any type composed entirely of Send types is automatically marked as Send as well. Almost all primitive types are Send, aside from raw pointers, which we’ll discuss in Chapter 20.

从多个线程进行访问

Accessing from Multiple Threads

Sync 标记 trait 表明实现了 Sync 的类型可以安全地被多个线程引用。换句话说,如果 &TT 的不可变引用)实现了 Send,则任何类型 T 都实现了 Sync,这意味着该引用可以安全地发送到另一个线程。与 Send 类似,原始类型都实现了 Sync,完全由实现 Sync 的类型组成的类型也实现了 Sync

The Sync marker trait indicates that it is safe for the type implementing Sync to be referenced from multiple threads. In other words, any type T implements Sync if &T (an immutable reference to T) implements Send, meaning the reference can be sent safely to another thread. Similar to Send, primitive types all implement Sync, and types composed entirely of types that implement Sync also implement Sync.

出于与不实现 Send 相同的原因,智能指针 Rc<T> 也不实现 SyncRefCell<T> 类型(我们在第 15 章讨论过)以及相关的 Cell<T> 类型系列也不实现 SyncRefCell<T> 在运行时执行的借用检查实现不是线程安全的。智能指针 Mutex<T> 实现了 Sync,可以用于在多个线程间共享访问,正如你在 “在多个线程间共享 Mutex<T> 中看到的。

The smart pointer Rc<T> also doesn’t implement Sync for the same reasons that it doesn’t implement Send. The RefCell<T> type (which we talked about in Chapter 15) and the family of related Cell<T> types don’t implement Sync. The implementation of borrow checking that RefCell<T> does at runtime is not thread-safe. The smart pointer Mutex<T> implements Sync and can be used to share access with multiple threads, as you saw in “Shared Access to Mutex<T>.

手动实现 SendSync 是不安全的

Implementing Send and Sync Manually Is Unsafe

因为完全由实现了 SendSync trait 的其他类型组成的类型也会自动实现 SendSync,所以我们不必手动实现这些 trait。作为标记 trait,它们甚至没有任何需要实现的方法。它们只是对于加强并发相关的约束很有用。

Because types composed entirely of other types that implement the Send and Sync traits also automatically implement Send and Sync, we don’t have to implement those traits manually. As marker traits, they don’t even have any methods to implement. They’re just useful for enforcing invariants related to concurrency.

手动实现这些 trait 涉及编写不安全的(unsafe)Rust 代码。我们将在第 20 章讨论使用不安全的 Rust 代码;目前,重要的信息是构建由非 SendSync 部分组成的新并发类型需要仔细思考以维护安全保证。“Rust 之书 (The Rustonomicon)” 有关于这些保证以及如何维护它们的更多信息。

Manually implementing these traits involves implementing unsafe Rust code. We’ll talk about using unsafe Rust code in Chapter 20; for now, the important information is that building new concurrent types not made up of Send and Sync parts requires careful thought to uphold the safety guarantees. “The Rustonomicon” has more information about these guarantees and how to uphold them.

总结

Summary

这并不是你在本书中最后一次看到并发:下一章侧重于异步编程,第 21 章的项目将会在比这里讨论的小示例更现实的情况下使用本章的概念。

This isn’t the last you’ll see of concurrency in this book: The next chapter focuses on async programming, and the project in Chapter 21 will use the concepts in this chapter in a more realistic situation than the smaller examples discussed here.

如前所述,因为 Rust 处理并发的方式很少是语言本身的一部分,所以许多并发解决方案都是作为 crate 实现的。这些 crate 的演进速度比标准库快,因此在多线程情况下,请务必在线搜索当前的尖端 crate。

As mentioned earlier, because very little of how Rust handles concurrency is part of the language, many concurrency solutions are implemented as crates. These evolve more quickly than the standard library, so be sure to search online for the current, state-of-the-art crates to use in multithreaded situations.

Rust 标准库提供了用于消息传递的通道,以及可在并发上下文中安全使用的智能指针类型,如 Mutex<T>Arc<T>。类型系统和借用检查器确保使用这些解决方案的代码不会以数据竞态或无效引用告终。一旦你让代码通过编译,你就可以放心,它将愉快地在多个线程上运行,而不会出现其他语言中常见的那些难以追踪的 bug。并发编程不再是一个令人恐惧的概念:放手去做,无畏地让你的程序并发运行吧!

The Rust standard library provides channels for message passing and smart pointer types, such as Mutex<T> and Arc<T>, that are safe to use in concurrent contexts. The type system and the borrow checker ensure that the code using these solutions won’t end up with data races or invalid references. Once you get your code to compile, you can rest assured that it will happily run on multiple threads without the kinds of hard-to-track-down bugs common in other languages. Concurrent programming is no longer a concept to be afraid of: Go forth and make your programs concurrent, fearlessly!