go - 使用多个扫描仪时,scanner.Scan()的顺序出现问题

标签 go buffer

在某些背景下,我对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() {
  ...
}

关于go - 使用多个扫描仪时,scanner.Scan()的顺序出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61622786/

相关文章:

java - 输入流仅返回 1 个字节

C:如何构建 line_buffer 才能不被覆盖?

mongodb - 查询期间文档的MongoDB求和字段

异步读取 SSH 输出

python - Cython:将 C 缓冲区内存 View 返回给 Python

OpenGL - 使用 index = 1 调用 glBindBufferBase 会中断渲染(黑色)

c - 从缓冲区读取数据的最佳实践

http - HTTP 代理是否应该将 Content-Encoding header 复制回客户端?

go - 如何在运行时从给定调用中查找包名称?

json - 从参数动态填充结构