如何从stdin读取非阻塞?

sma*_*arr 9 rust

有没有办法检查stdinRust中的数据是否可用,或者是否使用当前可用的数据进行立即返回的读取?

我的目标是能够读取由shell中的光标键产生的输入,该shell被设置为立即返回所有读取数据.例如,相当于: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 :(
Run Code Online (Sandbox Code Playgroud)

小智 9

将 OP 的评论转换为答案:

您可以生成一个线程并通过通道发送数据。然后,您可以使用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);
}
Run Code Online (Sandbox Code Playgroud)

  • @GünterZöchbauer 你不能。发生这种情况的可能性是这个简单解决方案的缺点。 (2认同)

Art*_*mGr 8

大多数操作系统默认以阻塞方式使用标准输入和输出。难怪 Rust 库取而代之。

要以非阻塞方式从阻塞流中读取,您可能会创建一个单独的线程,以便额外的线程阻塞而不是主线程。检查阻塞文件描述符是否产生一些输入是类似的:产生一个线程,让它读取数据,检查它到目前为止是否产生了任何数据。

是我使用的一段代码,它具有类似的目标,即交互式处理管道输出,希望可以作为示例。它通过支持try_recv方法的通道发送数据- 允许您检查数据是否可用。

有人告诉我mio可能用于以非阻塞方式从管道中读取数据,因此您可能也想查看一下。我怀疑将 stdin 文件描述符 (0) 传递给PipeReader::from_fd应该可以正常工作。