Rust tokio_serial:异步 fn 可读不会阻止执行。以 100% CPU 负载运行

问题描述 投票:0回答:1

我正在尝试使用 Rust 实现一些在 Linux PC 上处理 UART 通信的东西。这是我第一次用 Rust 写任何东西,所以我可能完全放弃了。

因为我的协议的通信有点异步,所以我想使用

tokio
。我发现了
tokio_serial
板条箱,它似乎将串行端口包装到异步可用的 API 中。

我尝试了以下代码。它应该在 uart 端口上接收数据并将其打印到控制台并回显字节。这很好用。

但是,我的程序在收到第一个字节后消耗了 100% CPU 负载。只要尚未接收到数据,它就可以正常工作并且不会消耗 CPU。我添加了注释掉的 println!声明并看到,

port.readable().await;
实际上不会阻塞,而是在没有任何实际可读数据的情况下完成。

我在这里做错了什么?

use std::{env, io::Write, process, str};
use tokio_serial::{self, SerialPortBuilderExt};

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let baud_rate : u32 = 115200;
    let serial_port = env::args().nth(1).unwrap_or_else(|| {String::from("/dev/ttyUSB0")});
    println!("Open port {serial_port}");

    let mut port = tokio_serial::new(serial_port, baud_rate).open_native_async().unwrap_or_else(
        |e| {
            println!("Error: {:?}", e);
            process::exit(-1);
        }
    );
    

    let mut buf : [u8; 255] = [0;255];
    loop {
        let readable_res = port.readable().await;
        if let Ok(()) = readable_res {
            match port.try_read(&mut buf) {
                Ok(size) => {
                    println!("Got {} bytes: {}", size, str::from_utf8(&buf[0..size]).unwrap());
                    port.write(&buf[0..size]).unwrap_or_else(|e| {println!("{:?}", e); 0});
                },
                Err(e) => {
                    //println!("{:?}", e);
                }
            }
        } 
    }
}
rust serial-port rust-tokio
1个回答
0
投票

readable
的文档非常清楚地说:“该函数可能在套接字不可读的情况下完成。这是一个误报......”换句话说,
readable
未来保证在以下情况下完成:套接字可以被读取,但如果它不能被读取,则保证完成。

如果您正在循环阅读,您可能应该使用

read
(通过
AsyncReadExt
)而不是
readable
+
try_read
。这要简单得多,也更容易正确。

无论如何,确实没有理由在异步上下文中执行非阻塞 I/O。在同步代码中,您通常使用非阻塞 I/O,因此您可以在等待 I/O 准备就绪时执行其他操作,但在异步上下文中,您可以在通过异步运行时等待时执行其他操作(任务、

join!
select!
等)。

© www.soinside.com 2019 - 2024. All rights reserved.