Ответ
В Go можно остановить чтение из канала (горутину-получателя) несколькими идиоматическими способами:
-
Закрытие канала отправителем. Это самый распространенный способ. Цикл
for range
по каналу автоматически завершится, когда канал будет закрыт.// Горутина-отправитель close(ch) // Горутина-получатель for val := range ch { // Цикл завершится, когда канал ch закроется // ... обработка val }
-
Использование
select
с каналомcontext.Done()
. Это лучший способ для управления жизненным циклом горутин, особенно в серверных приложениях. Отмена контекста сигнализирует горутине о необходимости завершиться.func worker(ctx context.Context, ch <-chan int) { for { select { case val := <-ch: fmt.Println("Обработка", val) case <-ctx.Done(): // Контекст был отменен fmt.Println("Получен сигнал завершения") return } } }
-
Использование отдельного "стоп"-канала. Классический паттерн, который использовался до широкого распространения
context
.func worker(ch <-chan int, done <-chan struct{}) { for { select { case val := <-ch: fmt.Println("Обработка", val) case <-done: // Получен сигнал из стоп-канала fmt.Println("Получен сигнал завершения") return } } } // В другом месте: close(done)
Важно: При чтении из канала всегда можно проверить, был ли он закрыт, с помощью второй переменной ok
:
val, ok := <-ch
if !ok {
// Канал закрыт и пуст. val будет нулевым значением для своего типа.
}