Есть произвольное число каналов. Нужно вернуть один канал, в который попадут
все значения из входных (порядок любой).
func Merge[T any](ctx context.Context, chans ...<-chan T) <-chan T
Требования
- В выходной канал попадает каждое значение из каждого входного ровно один раз.
- Выходной канал закрывается, когда закрыты и вычитаны все входные.
Если входов нет, возвращается сразу закрытый канал.
- Каналы читаются параллельно: пустой открытый канал не мешает получать
значения из остальных.
- При отмене
ctx выходной канал закрывается, а все горутины Merge
завершаются, даже если потребитель перестал читать выход.
- После завершения горутин не остаётся. Код проходит
go test -race.
Пример
a, b := make(chan int), make(chan int)
go func() { defer close(a); a <- 1; a <- 2 }()
go func() { defer close(b); b <- 10 }()
for v := range Merge(context.Background(), a, b) {
fmt.Println(v) // 1, 2, 10 в каком-то порядке
}
Каналов может быть тысячи, и держать горутину на каждый не хочется.
func MergeN[T any](ctx context.Context, readers int, chans ...<-chan T) <-chan T
- Входы читают не больше
readers горутин (readers < 1 считается как 1),
а не по одной на канал.
- Каналы опрашиваются по очереди. Если в канале сейчас нет данных, читатель не
ждёт на нём, а идёт к следующему и возвращается к пустому позже.
- Остальные требования те же, что у
Merge: все значения, закрытие выхода,
отмена через ctx, никаких утечек.
Разбор и эталонное решение — после своей попытки: на собеседовании подсказок не будет.
Сначала попробуй сам — подсказки не дают готовый ответ.