如何从 stdin 读取非阻塞?
How can I read non-blocking from stdin?
有没有办法在 Rust 中检查 stdin
上的数据是否可用,或者使用当前可用数据立即读取 returns?
我的目标是能够读取 shell 中光标键产生的输入,该 shell 设置为 return 立即读取所有数据。例如等效于:stty -echo -echok -icanon min 1 time 0
.
我想一个解决方案是使用 ncurses 或类似的库,但我想避免任何类型的大依赖。
到目前为止,我只得到阻塞输入,这不是我想要的:
let mut reader = stdin();
let mut s = String::new();
match reader.read_to_string(&mut s) {...} // this blocks :(
大多数操作系统默认以阻塞方式使用标准输入和输出。难怪 Rust 库会随之而来。
要以非阻塞方式从阻塞流中读取数据,您可以创建一个单独的线程,这样额外的线程就会阻塞而不是主线程。检查阻塞文件描述符是否产生了一些输入是类似的:产生一个线程,让它读取数据,检查它到目前为止是否产生了任何数据。
Here's a piece of code that I use with a similar goal of processing a pipe output interactively and that can hopefully serve as an example. It sends the data over a channel, which supports the try_recv 方法 - 允许您检查数据是否可用。
Someone has told me that mio might be used to read from a pipe in a non-blocking way, so you might want to check it out too. I suspect that passing the stdin file descriptor (0) to PipeReader::from_fd 应该可以。
您也可以考虑使用 ncurses (also on crates.io),这样您就可以在原始模式下阅读。 Github 存储库中有几个示例展示了如何执行此操作。
正在将 OP 的评论转换为答案:
您可以生成线程并通过 channel. You can then poll that channel in the main thread using try_recv.
发送数据
use std::io;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError;
use std::{thread, time};
fn main() {
let stdin_channel = spawn_stdin_channel();
loop {
match stdin_channel.try_recv() {
Ok(key) => println!("Received: {}", key),
Err(TryRecvError::Empty) => println!("Channel empty"),
Err(TryRecvError::Disconnected) => panic!("Channel disconnected"),
}
sleep(1000);
}
}
fn spawn_stdin_channel() -> Receiver<String> {
let (tx, rx) = mpsc::channel::<String>();
thread::spawn(move || loop {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).unwrap();
tx.send(buffer).unwrap();
});
rx
}
fn sleep(millis: u64) {
let duration = time::Duration::from_millis(millis);
thread::sleep(duration);
}
有没有办法在 Rust 中检查 stdin
上的数据是否可用,或者使用当前可用数据立即读取 returns?
我的目标是能够读取 shell 中光标键产生的输入,该 shell 设置为 return 立即读取所有数据。例如等效于:stty -echo -echok -icanon min 1 time 0
.
我想一个解决方案是使用 ncurses 或类似的库,但我想避免任何类型的大依赖。
到目前为止,我只得到阻塞输入,这不是我想要的:
let mut reader = stdin();
let mut s = String::new();
match reader.read_to_string(&mut s) {...} // this blocks :(
大多数操作系统默认以阻塞方式使用标准输入和输出。难怪 Rust 库会随之而来。
要以非阻塞方式从阻塞流中读取数据,您可以创建一个单独的线程,这样额外的线程就会阻塞而不是主线程。检查阻塞文件描述符是否产生了一些输入是类似的:产生一个线程,让它读取数据,检查它到目前为止是否产生了任何数据。
Here's a piece of code that I use with a similar goal of processing a pipe output interactively and that can hopefully serve as an example. It sends the data over a channel, which supports the try_recv 方法 - 允许您检查数据是否可用。
Someone has told me that mio might be used to read from a pipe in a non-blocking way, so you might want to check it out too. I suspect that passing the stdin file descriptor (0) to PipeReader::from_fd 应该可以。
您也可以考虑使用 ncurses (also on crates.io),这样您就可以在原始模式下阅读。 Github 存储库中有几个示例展示了如何执行此操作。
正在将 OP 的评论转换为答案:
您可以生成线程并通过 channel. You can then poll that channel in the main thread using try_recv.
发送数据use std::io;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError;
use std::{thread, time};
fn main() {
let stdin_channel = spawn_stdin_channel();
loop {
match stdin_channel.try_recv() {
Ok(key) => println!("Received: {}", key),
Err(TryRecvError::Empty) => println!("Channel empty"),
Err(TryRecvError::Disconnected) => panic!("Channel disconnected"),
}
sleep(1000);
}
}
fn spawn_stdin_channel() -> Receiver<String> {
let (tx, rx) = mpsc::channel::<String>();
thread::spawn(move || loop {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).unwrap();
tx.send(buffer).unwrap();
});
rx
}
fn sleep(millis: u64) {
let duration = time::Duration::from_millis(millis);
thread::sleep(duration);
}