如何对 io 进行非阻塞 Read()。PipeRaeder 在 Golang

How to do non-blocking Read() for io.PipeRaeder in Golang

提问人:Josh Chiu 提问时间:8/3/2023 更新时间:8/3/2023 访问量:105

问:

我有以下代码。可执行程序将在 5 秒后向 stdout 发送一些文本。所以,在。ReadLine() 将阻塞,直到收到数据。如何为 ReadLine() 设置超时或以非阻塞方式进行设置?

package main

import (
    "bufio"
    "fmt"
    "io"
    "os/exec"
)

func main() {
    cmd := exec.Command("/path/to/executable")

    stdoutReader, stdoutWriter := io.Pipe()

    cmd.Stdout = stdoutWriter

    cmd.Start()

    in := bufio.NewReader(stdoutReader)
    b, _, _ := in.ReadLine()

    fmt.Println(string(b))
}

去无 阻塞

评论

2赞 Cerise Limón 8/3/2023
在管道块上阅读。您要解决的更高层次的问题是什么?例如,您是否希望程序在超时未收到行时退出?
0赞 Josh Chiu 8/3/2023
我想每 10 秒读取一次可执行输出。如果可执行文件发送新数据,请将其打印出来。如果没有,请打印一个空字符串。
3赞 Volker 8/3/2023
在自己的 goroutine 中执行阻塞读取,并通过通道发送数据(一旦可用)。选择该频道和时间。股票。
0赞 Josh Chiu 8/3/2023
但是 ReaLine() 仍然阻塞,对吧?如果我想,每 1 秒执行一次 ReadLine(),如果没有收到数据,则打印“EMPTY”。可执行文件每 10 秒发送一次“HELLO”。如果得到 9 个“EMPTY”+ 1 个“HELLO”,我只会得到 1 个“HELLO”,对吧?

答:

1赞 Josh Chiu 8/3/2023 #1

感谢您的评论。我想通了。

package main

import (
    "bufio"
    "fmt"
    "io"
    "os/exec"
    "time"
)

func main() {
    ch := make(chan []byte)
    cmd := exec.Command("/path/to/executable")
    stdoutReader, stdoutWriter := io.Pipe()

    cmd.Stdout = stdoutWriter

    if err := cmd.Start(); err != nil {
        return
    }

    in := bufio.NewReader(stdoutReader)

    go func() {
        b, _, _ := in.ReadLine()
        ch <- b
    }()

    complete := false
    for !complete {
        select {
        case s := <-ch:
            fmt.Println(string(s))
            complete = true
        case <-time.After(time.Second * 5):
            fmt.Println("timeout")
            complete = true
        }
    }

}