Утечка 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
}()
Это приведет к блокировке горутина, того самого, чего вы пытаетесь избежать. Альтернатива состоит в том, что приложение пропускает ресурсы для каждой команды.