> Напиши функцию на Go, которая принимает слайс каналов int и возвращает канал с суммами чисел из каждого канала (Go)

Уровень: senior · Роль: backend · Категория: Технические вопросы

Компании: sferaplatform.ru

Стек: Go

> Пример ответа

Короткий ответ

Функция принимает []chan int, читает все значения из каждого канала, суммирует их и отправляет результат в выходной канал. Используем sync.WaitGroup для координации горутин и закрываем выходной канал после завершения всех чтений. Важно обработать закрытие входных каналов, чтобы избежать deadlock.

Подробное объяснение

Основная задача - конкурентно прочитать все каналы, просуммировать значения каждого канала отдельно и отправить сумму в общий выходной канал. Ключевые моменты:

  • Для каждого входного канала запускаем отдельную горутину.
  • Каждая горутина читает из своего канала до его закрытия, накапливая сумму.
  • После завершения чтения горутина отправляет сумму в выходной канал.
  • sync.WaitGroup позволяет дождаться завершения всех горутин перед закрытием выходного канала.
  • Выходной канал должен быть буферизированным или закрыт после завершения всех отправок, иначе потребитель может заблокироваться.

На практике

Типичный сценарий - агрегация результатов из нескольких источников данных. Например, сбор статистики с разных сервисов или обработка партиций. Важно помнить, что порядок сумм в выходном канале не гарантирован - он зависит от скорости чтения каждого входного канала. Если порядок важен, нужно передавать индекс канала вместе с суммой.

Пример кода

GO
func SumChannels(chs []chan int) chan int {
out := make(chan int, len(chs))
var wg sync.WaitGroup
for _, ch := range chs {
wg.Add(1)
go func(c chan int) {
defer wg.Done()
sum := 0
for v := range c {
sum += v
}
out <- sum
}(ch)
}
go func() {
wg.Wait()
close(out)
}()
return out
}

Использование:

GO
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
ch1 <- 1
ch1 <- 2
close(ch1)
}()
go func() {
ch2 <- 10
close(ch2)
}()
results := SumChannels([]chan int{ch1, ch2})
for sum := range results {
fmt.Println(sum) // 3 и 10 в произвольном порядке
}
}

Как отвечать на собеседовании

Начни с описания сигнатуры функции и подхода. Объясни, почему используешь sync.WaitGroup и зачем закрываешь выходной канал. Упомяни, что входные каналы должны быть закрыты отправителями - иначе горутины заблокируются. Если спросят про обработку паник или контекст отмены, предложи добавить context.Context для graceful shutdown.

Что проверяет интервьюер

  • Понимание конкурентности в Go: горутины, каналы, sync.WaitGroup.
  • Умение корректно закрывать каналы и избегать deadlock.
  • Знание особенностей работы с каналами: чтение из закрытого канала, буферизация.
  • Способность рассуждать о edge cases: пустой слайс, незакрытые каналы, порядок результатов.

Типичные ошибки

  • Забыть закрыть выходной канал - потребитель заблокируется навсегда.
  • Не использовать буфер для выходного канала - возможна блокировка при отправке, если потребитель медленный.
  • Передавать канал в горутину без копирования переменной цикла (в старых версиях Go) - все горутины будут читать из последнего канала.
  • Не обрабатывать случай пустого слайса - функция вернёт закрытый канал, что корректно, но может быть неожиданно.
  • Предполагать, что входные каналы будут закрыты - в реальном коде это нужно явно документировать.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью