Rust By Example 中的通道如何工作?
How do the channels work in Rust By Example?
我对 channel chapter of Rust by Example:
的输出感到很困惑
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;
static NTHREADS: i32 = 3;
fn main() {
// Channels have two endpoints: the `Sender<T>` and the `Receiver<T>`,
// where `T` is the type of the message to be transferred
// (type annotation is superfluous)
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
for id in 0..NTHREADS {
// The sender endpoint can be copied
let thread_tx = tx.clone();
// Each thread will send its id via the channel
thread::spawn(move || {
// The thread takes ownership over `thread_tx`
// Each thread queues a message in the channel
thread_tx.send(id).unwrap();
// Sending is a non-blocking operation, the thread will continue
// immediately after sending its message
println!("thread {} finished", id);
});
}
// Here, all the messages are collected
let mut ids = Vec::with_capacity(NTHREADS as usize);
for _ in 0..NTHREADS {
// The `recv` method picks a message from the channel
// `recv` will block the current thread if there no messages available
ids.push(rx.recv());
}
// Show the order in which the messages were sent
println!("{:?}", ids);
}
使用默认 NTHREADS = 3
,我得到以下输出:
thread 2 finished
thread 1 finished
[Ok(2), Ok(1), Ok(0)]
为什么for
循环中的println!("thread {} finished", id);
会倒序打印? thread 0 finished
去哪儿了?
当我改成NTHREADS = 8
的时候,更神秘的事情发生了:
thread 6 finished
thread 7 finished
thread 8 finished
thread 9 finished
thread 5 finished
thread 4 finished
thread 3 finished
thread 2 finished
thread 1 finished
[Ok(6), Ok(7), Ok(8), Ok(9), Ok(5), Ok(4), Ok(3), Ok(2), Ok(1), Ok(0)]
打印顺序更让我困惑,线程0总是不见了。这个例子怎么解释?
我在不同的电脑上试过,得到了相同的结果。
线程之间没有保证的顺序或它们之间的任何协调,因此它们将以任意顺序执行并将结果发送到通道中。这就是重点 - 如果它们是独立的,您可以使用多个线程。
主线程从通道中提取 N
值,将它们放入 Vec
,打印 Vec
并退出。
主线程不会等待子线程完成后再退出。丢失的打印解释为最后一个子线程将值发送到通道,主线程读取它(结束 for
循环),然后程序退出。线程从来没有机会打印完成。
也有可能最后一个线程有机会运行在主线程恢复退出前打印出来
根据 CPU 的数量或 OS,每个场景的可能性或多或少可能存在,但两者都是 正确 运行 的程序.
修改为等待线程的代码版本显示不同的输出:
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;
static NTHREADS: i32 = 3;
fn main() {
// Channels have two endpoints: the `Sender<T>` and the `Receiver<T>`,
// where `T` is the type of the message to be transferred
// (type annotation is superfluous)
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
let handles: Vec<_> = (0..NTHREADS).map(|id| {
// The sender endpoint can be copied
let thread_tx = tx.clone();
// Each thread will send its id via the channel
thread::spawn(move || {
// The thread takes ownership over `thread_tx`
// Each thread queues a message in the channel
thread_tx.send(id).unwrap();
// Sending is a non-blocking operation, the thread will continue
// immediately after sending its message
println!("thread {} finished", id);
})
}).collect();
// Here, all the messages are collected
let mut ids = Vec::with_capacity(NTHREADS as usize);
for _ in 0..NTHREADS {
// The `recv` method picks a message from the channel
// `recv` will block the current thread if there no messages available
ids.push(rx.recv());
}
// Show the order in which the messages were sent
println!("{:?}", ids);
// Wait for threads to complete
for handle in handles {
handle.join().expect("Unable to join");
}
}
请注意,在这种情况下,主线程如何在 最后一个线程退出之前 打印:
thread 2 finished
thread 1 finished
[Ok(2), Ok(1), Ok(0)]
thread 0 finished
这四行以 任何 顺序出现也是有效的:没有理由让任何子线程在主线程打印之前或之后打印。
我对 channel chapter of Rust by Example:
的输出感到很困惑use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;
static NTHREADS: i32 = 3;
fn main() {
// Channels have two endpoints: the `Sender<T>` and the `Receiver<T>`,
// where `T` is the type of the message to be transferred
// (type annotation is superfluous)
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
for id in 0..NTHREADS {
// The sender endpoint can be copied
let thread_tx = tx.clone();
// Each thread will send its id via the channel
thread::spawn(move || {
// The thread takes ownership over `thread_tx`
// Each thread queues a message in the channel
thread_tx.send(id).unwrap();
// Sending is a non-blocking operation, the thread will continue
// immediately after sending its message
println!("thread {} finished", id);
});
}
// Here, all the messages are collected
let mut ids = Vec::with_capacity(NTHREADS as usize);
for _ in 0..NTHREADS {
// The `recv` method picks a message from the channel
// `recv` will block the current thread if there no messages available
ids.push(rx.recv());
}
// Show the order in which the messages were sent
println!("{:?}", ids);
}
使用默认 NTHREADS = 3
,我得到以下输出:
thread 2 finished
thread 1 finished
[Ok(2), Ok(1), Ok(0)]
为什么for
循环中的println!("thread {} finished", id);
会倒序打印? thread 0 finished
去哪儿了?
当我改成NTHREADS = 8
的时候,更神秘的事情发生了:
thread 6 finished
thread 7 finished
thread 8 finished
thread 9 finished
thread 5 finished
thread 4 finished
thread 3 finished
thread 2 finished
thread 1 finished
[Ok(6), Ok(7), Ok(8), Ok(9), Ok(5), Ok(4), Ok(3), Ok(2), Ok(1), Ok(0)]
打印顺序更让我困惑,线程0总是不见了。这个例子怎么解释?
我在不同的电脑上试过,得到了相同的结果。
线程之间没有保证的顺序或它们之间的任何协调,因此它们将以任意顺序执行并将结果发送到通道中。这就是重点 - 如果它们是独立的,您可以使用多个线程。
主线程从通道中提取 N
值,将它们放入 Vec
,打印 Vec
并退出。
主线程不会等待子线程完成后再退出。丢失的打印解释为最后一个子线程将值发送到通道,主线程读取它(结束 for
循环),然后程序退出。线程从来没有机会打印完成。
也有可能最后一个线程有机会运行在主线程恢复退出前打印出来
根据 CPU 的数量或 OS,每个场景的可能性或多或少可能存在,但两者都是 正确 运行 的程序.
修改为等待线程的代码版本显示不同的输出:
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;
static NTHREADS: i32 = 3;
fn main() {
// Channels have two endpoints: the `Sender<T>` and the `Receiver<T>`,
// where `T` is the type of the message to be transferred
// (type annotation is superfluous)
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
let handles: Vec<_> = (0..NTHREADS).map(|id| {
// The sender endpoint can be copied
let thread_tx = tx.clone();
// Each thread will send its id via the channel
thread::spawn(move || {
// The thread takes ownership over `thread_tx`
// Each thread queues a message in the channel
thread_tx.send(id).unwrap();
// Sending is a non-blocking operation, the thread will continue
// immediately after sending its message
println!("thread {} finished", id);
})
}).collect();
// Here, all the messages are collected
let mut ids = Vec::with_capacity(NTHREADS as usize);
for _ in 0..NTHREADS {
// The `recv` method picks a message from the channel
// `recv` will block the current thread if there no messages available
ids.push(rx.recv());
}
// Show the order in which the messages were sent
println!("{:?}", ids);
// Wait for threads to complete
for handle in handles {
handle.join().expect("Unable to join");
}
}
请注意,在这种情况下,主线程如何在 最后一个线程退出之前 打印:
thread 2 finished
thread 1 finished
[Ok(2), Ok(1), Ok(0)]
thread 0 finished
这四行以 任何 顺序出现也是有效的:没有理由让任何子线程在主线程打印之前或之后打印。