首页 > 解决方案 > Go 扫描缓冲区有时会挂起

问题描述

我使用以下代码可以正常工作,但是在某些情况下,进程卡住了,我看不到任何输出。示例此代码运行npm installmvn clean install大部分时间运行良好,但有时它挂起并且您没有得到任何输出

func exec(stdout io.Reader, stderr io.Reader) (*bufio.Scanner, *bufio.Scanner) {
    scanout := bufio.NewScanner(stdout)
    scanerr := bufio.NewScanner(stderr)

    scanout.Split(bufio.ScanRunes)
    for scanout.Scan() {
        fmt.Print(scanout.Text())
    }

    scanerr.Split(bufio.ScanRunes)
    for scanerr.Scan() {
        fmt.Print(scanerr.Text())
    }
    return scanout, scanerr
}

现在,如果我像以下那样更改顺序(首先是错误,其次是标准输出),当命令挂起时我会得到一些错误输出,但是我没有在线看到输出,当你运行命令时你会看到一些输出,完成后你会看到所有其余的部分 。您可以等待输出 2 分钟或更长时间,然后在流程结束时立即获得较长的输出。

如何解决我将能够在线获取输出并在进程挂起时获得一些反馈的问题?

func exec(stdout io.Reader, stderr io.Reader) (*bufio.Scanner, *bufio.Scanner) {
    scanout := bufio.NewScanner(stdout)
    scanerr := bufio.NewScanner(stderr)

    scanout.Split(bufio.ScanRunes)
    for scanout.Scan() {
        fmt.Print(scanout.Text())
    }
    scanerr.Split(bufio.ScanRunes)
    for scanerr.Scan() {
        fmt.Print(scanerr.Text())
    }


    }
    return scanout, scanerr
}

更新

应该是这样吗?

func exec(stdout io.Reader, stderr io.Reader) (*bufio.Scanner, *bufio.Scanner) {

scanout := bufio.NewScanner(stdout)
scanout.Split(bufio.ScanRunes)
go func() {
    for scanout.Scan() {
        fmt.Print(scanout.Text())
     }
}()

go func() {
scanerr.Split(bufio.ScanRunes)
        for scanerr.Scan() {
            fmt.Print(scanerr.Text())
        }
}()

}

标签: go

解决方案


在第一种情况下,您正在从进程的标准输出中读取,直到进程结束。然后你从标准错误中读取。在第二种情况下,您首先从 err 读取,然后再读取。你应该读他们两个。要么使用 Cmd.CombinedOutput 来返回它们,要么启动两个 goroutine,一个从 stdin 读取,一个从 stderr 读取,直到流关闭。

scanout := bufio.NewScanner(stdout)
scanout.Split(bufio.ScanRunes)
go func() {
    for scanout.Scan() {
        fmt.Print(scanout.Text())
     }
}()

推荐阅读