Update Ch20

This commit is contained in:
Unisko PENG 2023-04-06 14:36:45 +08:00
parent 9b46dc2e4b
commit 4a1fdc6d39

View File

@ -1139,8 +1139,28 @@ Worker 1 获取到一项作业;执行中。
> 注意:若咱们在多个窗口同时打开 `/sleep`,他们可能会在设置的时间间隔每次加载一个。有些 web 浏览器会出于缓存原因,而顺序执行同一请求的多个实例。这样的局限并不是由咱们的服务器导致的。
在了解了第 18 章中的 `while let` 循环后,咱们可能想知道,为何咱们没有如下清单 20-21 中所示的那样,编写 `worker` 线程的代码。
文件名:`src/lib.rs`
这段代码将会编译及运行,但不会产生所需的线程行为:慢速请求仍将导致别的请求等待被处理。至于原因则有点微妙:由于锁的所有权是基于 `lock` 方法返回的 `LockResult<MutexGuard<T>>` 中,`MutexGuard<T>` 的生命周期,因此这个 `Mutex` 结构体没有公开的 `unlock` 方法。在编译时,借用检查器可于随后,就除非咱们拿着 `Mutex` 所守卫的某项资源的锁,否则无法访问该项资源这一规矩强制加以检查。但是,若咱们没有注意到 `MutexGuard<T>` 的生命周期,那么这样的实现同样能导致锁相较预期被占用更长时间。
```rust
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
let thread = thread::spawn(move || {
while let Ok(job) = receiver.lock().unwrap().recv() {
println! ("Worker {id} 获取到一项作业;执行中。");
由于在 `let` 之下,等号右侧的表达式中用到的任何临时值,都会在 `let` 语句结束时被立即丢弃,因此使用了 `let job = receiver.lock().unwrap().recv().unwrap();` 的清单 20-20 中代码是工作的。但是,`while let`(以及 `if let``match` 则是在相关代码块结束前,不会丢弃那些临时值。在清单 20-21 中,
job();
}
});
Worker { id, thread }
}
}
```
*清单 20-21使用 `while let` 的一种 `Worker::new` 替代实现*
这段代码将会编译及运行,但不会产生所需的线程行为:慢速请求仍将导致别的请求等待被处理。至于原因则有点微妙:由于锁的所有权是基于 `lock` 方法返回的 `LockResult<MutexGuard<T>>` 中,`MutexGuard<T>` 的生命周期,因此这个 `Mutex` 结构体没有公开的 `unlock` 方法。在编译时,借用检查器可于随后,就除非咱们拿着 `Mutex` 所守卫的某项资源的锁,否则无法访问该项资源这一规则强制加以检查。但是,若咱们没有注意到 `MutexGuard<T>` 的生命周期,那么这样的实现同样能导致锁相较预期被占用更长时间。
由于在 `let` 之下,等号右侧的表达式中用到的任何临时值,都会在 `let` 语句结束时被立即丢弃,因此使用了 `let job = receiver.lock().unwrap().recv().unwrap();` 的清单 20-20 中代码是工作的。但是,`while let`(以及 `if let``match` 则是在相关代码块结束前,不会丢弃那些临时值。在清单 20-21 中,锁会在到 `job()` 的调用其将保持被持有,这意味着别的 `worker` 就没法收到作业。