如何异步读取子进程输出

时间:2018-03-12 23:20:37

标签: asynchronous rust stdio rust-tokio

我想实现一个futures::Stream来读取和解析子子进程的标准输出。

我现在在做什么:

  • 生成子流程并通过std::process方法获取其标准输出:let child = Command::new(...).stdout(Stdio.pipe()).spawn().expect(...)

  • AsyncReadBufRead添加到stdout:

    let stdout = BufReader::new(tokio_io::io::AllowStdIo::new(
        child.stdout.expect("Failed to open stdout"),
    ));
    
  • 为stdout声明一个包装结构:

    struct MyStream<Io: AsyncRead + BufRead> {
        io: Io,
    }
    
  • 实施Stream

    impl<Io: AsyncRead + BufRead> Stream for MyStream<Io> {
        type Item = Message;
        type Error = Error;
    
        fn poll(&mut self) -> Poll<Option<Message>, Error> {
            let mut line = String::new();
            let n = try_nb!(self.io.read_line(&mut line));
            if n == 0 {
                return Ok(None.into());
            }
            //...read & parse further
        }
    }
    

问题是AllowStdIo不会使ChildStdout神奇地异步,而self.io.read_line调用仍会阻止。

我想我需要传递一些不同的东西而不是Stdio::pipe()才能让它异步,但是什么呢?或者是否有不同的解决方案?

这个问题与What is the best approach to encapsulate blocking I/O in future-rs?不同,因为我希望针对子进程的特定情况获得异步I / O,而不是解决同步I / O的封装问题。

更新:我正在使用tokio = "0.1.3"来利用其运行时功能,目前使用tokio-process不是一个选项(https://github.com/alexcrichton/tokio-process/issues/27

1 个答案:

答案 0 :(得分:2)

tokio-process crate为您提供CommandExt特征,允许您异步生成命令。

生成的ChildChildStdout的getter,它实现Read并且是非阻塞的。

如您在示例中所做的那样将tokio_process::ChildStdout包装到AllowStdIo中应该可以使其正常工作!

相关问题