From a3ae2f9fd42cb151516fcebc591dcd24967e8e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BB=E8=AF=AD?= Date: Thu, 29 May 2025 18:36:28 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=85=B3=E8=81=94?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E7=9A=84=E6=96=87=E5=AD=97=E8=8C=83=E5=9B=B4?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch16-02-message-passing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch16-02-message-passing.md b/src/ch16-02-message-passing.md index f4b62dc..33b4ee7 100644 --- a/src/ch16-02-message-passing.md +++ b/src/ch16-02-message-passing.md @@ -3,7 +3,7 @@ -一个日益流行的确保安全并发的方式是**消息传递**(_message passing_),这里线程或 actor 通过发送包含数据的消息来相互沟通。这个思想来源于 [Go 编程语言文档中](https://golang.org/doc/effective_go.html#concurrency) 的口号:“不要通过共享内存来通讯;而要通过通讯来共享内存。”(“Do not communicate by sharing memory; instead, share memory by communicating.”) +一个日益流行的确保安全并发的方式是**消息传递**(_message passing_),这里线程或 actor 通过发送包含数据的消息来相互沟通。这个思想来源于 [Go 编程语言文档](https://golang.org/doc/effective_go.html#concurrency) 中的口号:“不要通过共享内存来通讯;而要通过通讯来共享内存。”(“Do not communicate by sharing memory; instead, share memory by communicating.”) 为了实现消息传递并发,Rust 标准库提供了一个**信道**(_channel_)实现。信道是一个通用编程概念,表示数据从一个线程发送到另一个线程。 From 09e780edb9e363e2a9742a46da1e2c6732d1fdcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BB=E8=AF=AD?= Date: Thu, 29 May 2025 19:12:43 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5=E9=94=99=E8=AF=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch16-02-message-passing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch16-02-message-passing.md b/src/ch16-02-message-passing.md index 33b4ee7..4350a69 100644 --- a/src/ch16-02-message-passing.md +++ b/src/ch16-02-message-passing.md @@ -9,7 +9,7 @@ 你可以将编程中的信道想象为一个水流的渠道,比如河流或小溪。如果你将诸如橡皮鸭之类的东西放入其中,它们会顺流而下到达下游。 -信道由两个组成部分:一个发送端(transmitter)和一个接收端(receiver)。发送端位于上游位置,在这里可以将橡皮鸭放入河中,接收端则位于下游,橡皮鸭最终会漂流至此。代码中的一部分调用发送端的方法以及希望发送的数据,另一部分则检查接收端收到的消息。当发送端或接收端任一被丢弃时可以认为信道被**关闭**(_closed_)了。 +信道有两个组成部分:一个发送端(transmitter)和一个接收端(receiver)。发送端位于上游位置,在这里可以将橡皮鸭放入河中,接收端则位于下游,橡皮鸭最终会漂流至此。代码中的一部分调用发送端的方法以及希望发送的数据,另一部分则检查接收端收到的消息。当发送端或接收端任一被丢弃时可以认为信道被**关闭**(_closed_)了。 这里,我们将开发一个程序,它会在一个线程生成值向信道发送,而在另一个线程会接收值并打印出来。这里会通过信道在线程间发送简单值来演示这个功能。一旦你熟悉了这项技术,你就可以将信道用于任何相互通信的任何线程,例如一个聊天系统,或利用很多线程进行分布式计算并将部分计算结果发送给一个线程进行聚合。 From 33a684338f337fbc6756890c04f998c3b50d782f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BB=E8=AF=AD?= Date: Thu, 29 May 2025 22:27:13 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ch16-03-shared-state.md | 4 ++-- src/ch16-04-extensible-concurrency-sync-and-send.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch16-03-shared-state.md b/src/ch16-03-shared-state.md index 2ad2122..e325b11 100644 --- a/src/ch16-03-shared-state.md +++ b/src/ch16-03-shared-state.md @@ -38,7 +38,7 @@ 如果另一个线程拥有锁,并且那个线程 panic 了,则 `lock` 调用会失败。在这种情况下,没人能够再获取锁,所以我们调用 `unwrap`,使当前线程 panic。 -一旦获取了锁,就可以将返回值(命名为 `num`)视为一个其内部数据的可变引用了。类型系统确保了我们在使用 `m` 中的值之前获取锁。`m` 的类型是 `Mutex` 而不是 `i32`,所以**必须**调用 `lock` 才能使用这个 `i32` 值。我们不能忘记这么做的;因为如果没有获取锁,类型系统就不允许访问内部的 `i32` 值。 +一旦获取了锁,就可以将返回值(命名为 `num`)视为一个其内部数据的可变引用了。类型系统确保了我们在使用 `m` 中的值之前获取锁。`m` 的类型是 `Mutex` 而不是 `i32`,所以**必须**调用 `lock` 才能使用这个 `i32` 值。我们不能忘记这么做,因为如果没有获取锁,类型系统就不允许访问内部的 `i32` 值。 正如你所猜想的,`Mutex` 是一个智能指针。更准确的说,`lock` 调用会**返回**一个叫做 `MutexGuard` 的智能指针。`MutexGuard` 智能指针实现了 `Deref` 来指向其内部数据;它也实现了 `Drop`,当 `MutexGuard` 离开作用域时,自动释放锁(发生在示例 16-12 内部作用域的结尾)。这样一来,就不会有忘记释放锁从而导致互斥器阻塞无法被其他线程使用的潜在风险,因为锁的释放是自动发生的。 @@ -94,7 +94,7 @@ 所幸 `Arc` 正是这么一个类似 `Rc` 并可以安全地用于并发环境的类型。字母 _a_ 代表 **原子性**(_atomic_),所以这是一个**原子引用计数**(_atomically reference counted_)类型。**原子类型** (Atomics) 是另一类这里还未涉及到的并发原语:请查看标准库中 [`std::sync::atomic`][atomic] 的文档来获取更多细节。目前我们只需要知道:原子类型就像基本类型一样,可以安全地在线程间共享。 -你可能会好奇,为什么不是所有的基本类型都是原子性的?为什么标准库中的类型没有全部默认使用 `Arc` 实现?原因在于,线程安全会造成性能损失,我们希望只在必要时才为此买单。如果只是在单线程中对值进行操作,如果不必强制原子性所提供的保证可以使代码运行得更快。 +你可能会好奇,为什么不是所有的基本类型都是原子性的?为什么标准库中的类型没有全部默认使用 `Arc` 实现?原因在于,线程安全会造成性能损失,我们希望只在必要时才为此买单。如果只是在单线程中对值进行操作,不必强制原子性所提供的保证可以使代码运行得更快。 回到之前的例子:`Arc` 和 `Rc` 有着相同的 API,所以我们只需修改程序中的 `use` 行、`new` 调用和 `clone` 调用。示例 16-15 中的代码最终可以编译并运行。 diff --git a/src/ch16-04-extensible-concurrency-sync-and-send.md b/src/ch16-04-extensible-concurrency-sync-and-send.md index 9cf4b46..1fb723a 100644 --- a/src/ch16-04-extensible-concurrency-sync-and-send.md +++ b/src/ch16-04-extensible-concurrency-sync-and-send.md @@ -29,11 +29,11 @@ Rust 的并发模型中一个有趣的方面是:我们之前讨论的几乎所 ## 总结 -这不会是本书最后一个出现并发的章节:下一章会我们会专注于异步编程,并且第二十一章的项目会在更现实的场景中使用这些概念,而不像本章中讨论的这些小例子。 +这不会是本书最后一个出现并发的章节:下一章我们会专注于异步编程,并且第二十一章的项目会在更现实的场景中使用这些概念,而不像本章中讨论的这些小例子。 正如之前提到的,因为 Rust 本身很少有处理并发的部分内容,有很多的并发方案都由 crate 实现。它们比标准库要发展的更快;请在网上搜索当前最新的用于多线程场景的 crate。 -Rust 提供了用于消息传递的信道,和像 `Mutex` 和 `Arc` 这样可以安全的用于并发上下文的智能指针。类型系统和借用检查器会确保这些场景中的代码,不会出现数据竞争和无效的引用。一旦代码可以编译了,我们就可以坚信这些代码可以正确地运行于多线程环境,而不会出现其他语言中经常出现的那些难以追踪的 bug。并发编程不再是什么可怕的概念:无所畏惧地并发起来吧! +Rust 提供了用于消息传递的信道,和像 `Mutex` 和 `Arc` 这样可以安全的用于并发上下文的智能指针。类型系统和借用检查器会确保这些场景中的代码不会出现数据竞争和无效的引用。一旦代码可以编译了,我们就可以坚信这些代码可以正确地运行于多线程环境,而不会出现其他语言中经常出现的那些难以追踪的 bug。并发编程不再是什么可怕的概念:无所畏惧地并发起来吧! [sharing-a-mutext-between-multiple-threads]: ch16-03-shared-state.html#在多个线程间共享-mutext [nomicon]: https://doc.rust-lang.org/nomicon/index.html