Проблемы с порядком использования scanner.Scan () при использовании нескольких сканеров - PullRequest
1 голос
/ 05 мая 2020

Для некоторой предыстории, я новичок в Go, но человек, который написал эту программу на работе, ушел, так что теперь я отвечаю за код. Эта программа является оболочкой для инструмента CLI, который выполняет запись в stdout и stderr. Мы хотим обрабатывать вывод, а также корректно обрабатывать ошибки базового инструмента.

Это соответствующий фрагмент кода, который в настоящее время используется:

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 КБ, программа просто зависает без ошибок. Базовая команда завершается, но ни один из сканеров циклов не выполняется. Я обнаружил, что если поменять местами 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()

Кто-нибудь знает, почему возникает первоначальная проблема и почему замена двух сканеров решает ее? Я предполагал, что два сканера используют один и тот же базовый буфер, который может вызывать некоторые проблемы, но я создал два разных буфера и назначил их сканерам, и это не устранило проблему.

Любая помощь оценен!

1 Ответ

2 голосов
/ 06 мая 2020

Как написано, ваша программа будет ждать, пока все данные не будут прочитаны из одного из потоков, в зависимости от порядка. Если при чтении из этого потока второй буфер потока заполняется, запущенная программа (та, чей вывод вы читаете) будет заблокирована, потому что она не может больше записывать вывод в этот поток.

Похоже, вы на самом деле не обрабатываете ошибки, поэтому вы можете прочитать поток ошибок в горутине:

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

for scanner.Scan() {
  ...
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...