Канал завершения
Как вы знаете, с помощью done-канала горутина сигнализирует вызывающему, что закончила работать.
Есть пара вариантов реализации.
➊ Принимаем done-канал на входе:
func worker1(done chan struct{}) {
// do work
time.Sleep(10 * time.Millisecond)
close(done)
}
done := make(chan struct{})
go worker1(done)
<-done
➋ Возвращаем done-канал из функции:
func worker2() chan struct{} {
done := make(chan struct{})
go func() {
// do work
time.Sleep(10 * time.Millisecond)
close(done)
}()
return done
}
done := worker2()
<-done
У вас есть предпочтения? Сейчас расскажу о моих.
Кто канал создал, тот и закрывает
В Go есть одна эвристика, которую лучше не нарушать без веских причин: кто канал создал, тот и закрывает.
Поэтому мне больше по душе такая реализация канала завершения:
func work() <-chan struct{} {
done := make(chan struct{})
go func() {
// do work
time.Sleep(10 * time.Millisecond)
close(done)
}()
return done
}
done := work()
<-done
Если нужно не просто сигнализировать о завершении, а возвращать значение — заменяем chan struct{} на нужный тип вроде chan int, и готово.
А если хотим возвращать еще и ошибку, то так:
type Result[T any] struct {
Value T
Err error
}
func work() <-chan Result[int] {
out := make(chan Result[int], 1)
go func() {
// do work
time.Sleep(10 * time.Millisecond)
out <- Result[int]{Value: 42}
close(out)
}()
return out
}
out := work()
result := <-out
fmt.Println(result)
// {42 <nil>}
Удобно!
★ Подписывайтесь на новые заметки.