Утечка goroutine, когда висит неблокирующая readline

Предполагая, что у вас есть такая структура:

ch := make(chan string)
errCh := make(chan error)
go func() {
    line, _, err := bufio.NewReader(r).ReadLine()
    if err != nil {
        errCh <- err
    } else {
        ch <- string(line)
    }
}()
select {
case err := <-errCh:
    return "", err
case line := <-ch:
    return line, nil
case <-time.After(5 * time.Second):
    return "", TimeoutError
}

В случае 5-секундного таймаута, программа будет зависать до тех пор, пока ReadLine не вернется, что может никогда не произойти. Мой проект - долго работающий сервер, поэтому я не хочу накапливать застрявшие программы.

1 ответ

Решение

ReadLine не вернется, пока не завершится процесс или метод не прочитает строку. Там нет никакого срока или механизма тайм-аута для труб.

Программа будет заблокирована, если вызов ReadLine вернется после истечения времени ожидания. Это можно исправить с помощью буферизованных каналов:

ch := make(chan string, 1)
errCh := make(chan error, 1)

Приложение должно вызвать Wait для очистки ресурсов, связанных с командой. Goroutine - хорошее место, чтобы назвать это:

go func() {
  line, _, err := bufio.NewReader(r).ReadLine()
  if err != nil {
    errCh <- err
  } else {
    ch <- string(line)
  }
  cmd.Wait() // <-- add this line
}()

Это приведет к блокировке горутина, того самого, чего вы пытаетесь избежать. Альтернатива состоит в том, что приложение пропускает ресурсы для каждой команды.

Другие вопросы по тегам