From cf62c619c00db662e222a613cc0d859eea068643 Mon Sep 17 00:00:00 2001 From: Nango Date: Sun, 19 Jul 2020 03:08:43 -0500 Subject: [PATCH] Update ch16-01-threads.md --- src/ch16-01-threads.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ch16-01-threads.md b/src/ch16-01-threads.md index e75971b..c253055 100644 --- a/src/ch16-01-threads.md +++ b/src/ch16-01-threads.md @@ -19,7 +19,7 @@ Rust 尝试减轻使用线程的负面影响。不过在多线程上下文中编 每一个模型都有其优势和取舍。对于 Rust 来说最重要的取舍是运行时支持。**运行时**(_Runtime_)是一个令人迷惑的概念,其在不同上下文中可能有不同的含义。 -在当前上下文中,**运行时** 代表二进制文件中包含的由语言自身提供的代码。这些代码根据语言的不同可大可小,不过任何非汇编语言都会有一定数量的运行时代码。为此,通常人们说一个语言 “没有运行时”,一般意味着 “小运行时”。更小的运行时拥有更少的功能不过其优势在于更小的二进制输出,这使其易于在更多上下文中与其他语言相结合。虽然很多语言觉得增加运行时来换取更多功能没有什么问题,但是 Rust 需要做到几乎没有运行时,同时为了保持高性能必需能够调用 C 语言,这点也是不能妥协的。 +在当前上下文中,**运行时** 代表二进制文件中包含的由语言自身提供的代码。这些代码根据语言的不同可大可小,不过任何非汇编语言都会有一定数量的运行时代码。为此,通常人们说一个语言 “没有运行时”,一般意味着 “小运行时”。更小的运行时拥有更少的功能不过其优势在于更小的二进制输出,这使其易于在更多上下文中与其他语言相结合。虽然很多语言觉得增加运行时来换取更多功能没有什么问题,但是 Rust 需要做到几乎没有运行时,同时为了保持高性能必须能够调用 C 语言,这点也是不能妥协的。 绿色线程的 M:N 模型需要更大的语言运行时来管理这些线程。因此,Rust 标准库只提供了 1:1 线程模型实现。由于 Rust 是较为底层的语言,如果你愿意牺牲性能来换取抽象,以获得对线程运行更精细的控制及更低的上下文切换成本,你可以使用实现了 M:N 线程模型的 crate。 @@ -68,7 +68,7 @@ hi number 5 from the spawned thread! `thread::sleep` 调用强制线程停止执行一小段时间,这会允许其他不同的线程运行。这些线程可能会轮流运行,不过并不保证如此:这依赖操作系统如何调度线程。在这里,主线程首先打印,即便新创建线程的打印语句位于程序的开头,甚至即便我们告诉新建的线程打印直到 `i` 等于 9 ,它在主线程结束之前也只打印到了 5。 -如果运行代码只看到了主线程的输出,或没有出现重叠打印的现象,尝试增加 range 的数值来增加操作系统切换线程的机会。 +如果运行代码只看到了主线程的输出,或没有出现重叠打印的现象,尝试增大区间 (变量 `i` 的范围) 来增加操作系统切换线程的机会。 #### 使用 `join` 等待所有线程结束 @@ -164,7 +164,7 @@ hi number 3 from the main thread! hi number 4 from the main thread! ``` -稍微考虑一下将 `join` 放置于何处这样一个细节会影响线程是否同时运行。 +诸如将 `join` 放置于何处这样的小细节,会影响线程是否同时运行。 ### 线程与 `move` 闭包 @@ -247,7 +247,7 @@ variables), use the `move` keyword | ^^^^^^^ ``` -通过在闭包之前增加 `move` 关键字,我们强制闭包获取其使用的值的所有权,而不是任由 Rust 推断它应该借用值。示例 16-5 中展示的对示例 16-3 代码的修改,这可以按照我们的预期编译并运行: +通过在闭包之前增加 `move` 关键字,我们强制闭包获取其使用的值的所有权,而不是任由 Rust 推断它应该借用值。示例 16-5 中展示的对示例 16-3 代码的修改,可以按照我们的预期编译并运行: 文件名: src/main.rs @@ -267,7 +267,7 @@ fn main() { 示例 16-5: 使用 `move` 关键字强制获取它使用的值的所有权 -那么如果使用了 `move` 闭包,示例 16-4 中主线程调用了 `drop` 的代码会发生什么呢?不幸的是,我们会因为示例 16-4 尝试进行由于不同的原因所不允许的操作而得到不同的错误。如果为闭包增加 `move`,将会把 `v` 移动进闭包的环境中,如此将不能在主线程中对其调用 `drop` 了。我们会得到如下不同的编译错误: +那么如果使用了 `move` 闭包,示例 16-4 中主线程调用了 `drop` 的代码会发生什么呢?加了 `move` 就搞定了吗?不幸的是,我们会得到一个不同的错误,因为示例 16-4 所尝试的操作由于一个不同的原因而不被允许。如果为闭包增加 `move`,将会把 `v` 移动进闭包的环境中,如此将不能在主线程中对其调用 `drop` 了。我们会得到如下不同的编译错误: ```text error[E0382]: use of moved value: `v` @@ -283,6 +283,6 @@ error[E0382]: use of moved value: `v` not implement the `Copy` trait ``` -Rust 的所有权规则又一次帮助了我们!示例 16-3 中的错误是因为 Rust 是保守的并只会为线程借用 `v`,这意味着主线程理论上可能使新建线程的引用无效。通过告诉 Rust 将 `v` 的所有权移动到新建线程,我们向 Rust 保证主线程不会再使用 `v`。如果对示例 16-4 也做出如此修改,那么当在主线程中使用 `v` 时就会违反所有权规则。 `move` 关键字覆盖了 Rust 默认保守的借用:它不允许我们违反所有权规则。 +Rust 的所有权规则又一次帮助了我们!示例 16-3 中的错误是因为 Rust 是保守的并只会为线程借用 `v`,这意味着主线程理论上可能使新建线程的引用无效。通过告诉 Rust 将 `v` 的所有权移动到新建线程,我们向 Rust 保证主线程不会再使用 `v`。如果对示例 16-4 也做出如此修改,那么当在主线程中使用 `v` 时就会违反所有权规则。 `move` 关键字覆盖了 Rust 默认保守的借用,但它不允许我们违反所有权规则。 现在我们对线程和线程 API 有了基本的了解,让我们讨论一下使用线程实际可以 **做** 什么吧。