从管道读取的非阻塞方式

时间:2019-06-08 15:08:48

标签: go

我想创建一个简单的应用程序,它将连续读取一个应用程序的输出,对其进行处理并将处理后的输出写入stdout。这个应用程式可以在一秒钟内产生大量资料,而接下来的几分钟则保持静音状态。

问题在于,地雷数据处理算法非常慢,因此主循环被阻塞。当循环被阻塞时,我正在丢失即将到来的数据。

    cmd := exec.Command("someapp")
    stdoutPipe, _ := cmd.StdoutPipe()
    stdoutReader := bufio.NewReader(stdoutPipe)

    go func() {
        bufioReader := bufio.NewReader(stdoutReader)
        for {
            output, _, err := bufioReader.ReadLine()
            if err != nil || err == io.EOF {
                break
            }

            processedOutput := dataProcessor(output);

            fmt.Print(processedOutput)
        }
    }()

解决此问题的最佳方法可能是缓冲所有输出并在另一个Goroutine中对其进行处理,但是我不确定如何在Golang中实现此输出。解决此问题的最惯用的方法是什么?

1 个答案:

答案 0 :(得分:0)

您可以有两个goroutine,一个是供应商,另一个是消费者。供应商执行命令并通过通道将数据传递给消费者。

    cmd := exec.Command("someapp")
    stdoutPipe, _ := cmd.StdoutPipe()
    stdoutReader := bufio.NewReader(stdoutPipe)
    Datas := make(chan Data, 100)
    go dataProcessor(Datas)
        bufioReader := bufio.NewReader(stdoutReader)
        for {
            output, _, err := bufioReader.ReadLine()
            var tempData Data
            tempData.Out = output
            if err != nil || err == io.EOF {
                break
            }
            Datas <- tempData
            }
    }

然后将在dataProcessor函数中处理数据:

func dataProcessor(Datas <-chan Data)  {
    for  {
        select {
        case data := <-Datas:
        fmt.Println(data)
        default:
            continue
        }
    }
}

很明显,这是一个非常简单的示例,您应该对其进行自定义并使其更好。搜索有关chanle和goroutins的信息。阅读this教程可能会有所帮助。