使用多个扫描仪时 scanner.Scan() 的顺序问题

Issues with order of scanner.Scan() when using multiple scanners

对于一些背景知识,我是 Go 的新手,但是编写这个程序的人在工作中离开了,所以代码现在是我的责任。该程序包装了一个写入 stdout 和 stderr 的 CLI 工具。我们希望在处理输出的同时优雅地处理底层工具的错误。

这是当前正在使用的相关代码片段:

cmd := exec.Command(args[0], args[1:]...)

stdout, err := cmd.StdoutPipe()
if err != nil {
        log.Fatal(err)
}

stderr, err := cmd.StderrPipe()
if err != nil {
        log.Fatal(err)
}

cmd.Start()

scanner := bufio.NewScanner(stdout)
errScanner := bufio.NewScanner(stderr)

for errScanner.Scan() {
        err := errScanner.Text()
        log.Fatal(err)
}

for scanner.Scan() {
        // proccess stdout data
}

if scanner.Err() != nil {
        log.Fatal(scanner.Err())
}

cmd.Wait()

通常这可以正常工作。但是,如果写入标准输出的数据大小超过 buf.MaxScanTokenSize,即 64 KB,则程序会挂起而不会出现错误。底层命令完成,但没有命中循环扫描器。我发现如果我交换 errScanner.Scan() 和 scanner.Scan() 的位置,那么问题就不会再出现了。这就是我的意思:

cmd := exec.Command(args[0], args[1:]...)

stdout, err := cmd.StdoutPipe()
if err != nil {
        log.Fatal(err)
}

stderr, err := cmd.StderrPipe()
if err != nil {
        log.Fatal(err)
}

cmd.Start()

scanner := bufio.NewScanner(stdout)
errScanner := bufio.NewScanner(stderr)

for scanner.Scan() {
        // proccess stdout
}

for errScanner.Scan() {
        err := errScanner.Text()
        log.Fatal(err)
}

if scanner.Err() != nil {
        log.Fatal(scanner.Err())
}

cmd.Wait()

有谁知道为什么会出现最初的问题以及为什么交换两个扫描仪可以解决问题?我的猜测是两个扫描器共享相同的底层缓冲区,这可能会导致一些问题,但我创建了两个不同的缓冲区并将它们分配给扫描器,但它没有解决问题。

感谢任何帮助!

按照它的编写方式,您的程序将等待直到从其中一个流中读取所有数据,具体取决于顺序。如果从该流读取时第二个流缓冲区已满,则 运行 程序(您正在读取其输出的程序)将阻塞,因为它无法向该流写入更多输出。

看起来你并没有真正处理错误,所以你可以在 goroutine 中读取错误流:

go () {
  for errScanner.Scan() {
     ...
  }
}()

for scanner.Scan() {
  ...
}