> Как реализовать паттерн fan-out fan-in в Go с использованием горутин? (Go)

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

Компании: Axel Pro

Стек: Go

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

Для реализации паттерна fan-out fan-in в Go создаются несколько горутин-воркеров (fan-out), которые обрабатывают данные из общего входного канала, и одна горутина-агрегатор (fan-in), собирающая результаты в единый выходной канал.

Пример реализации:

GO
package main
import (
"fmt"
"sync"
)
// fanOut запускает n воркеров, читающих из входного канала
func fanOut(input <-chan int, n int) []<-chan int {
channels := make([]<-chan int, n)
for i := 0; i < n; i++ {
ch := make(chan int)
channels[i] = ch
go func(workerID int, out chan<- int) {
for val := range input {
// Обработка данных (например, умножение на 2)
result := val * 2
fmt.Printf("Worker %d обработал: %d -> %d\n", workerID, val, result)
out <- result
}
close(out)
}(i, ch)
}
return channels
}
// fanIn собирает данные из нескольких каналов в один
func fanIn(channels ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
wg.Add(len(channels))
for _, ch := range channels {
go func(c <-chan int) {
defer wg.Done()
for val := range c {
out <- val
}
}(ch)
}
// Закрываем выходной канал после завершения всех воркеров
go func() {
wg.Wait()
close(out)
}()
return out
}
func main() {
// Создаём входной канал
input := make(chan int)
// Запускаем fan-out с 3 воркерами
workerChannels := fanOut(input, 3)
// Запускаем fan-in для сбора результатов
results := fanIn(workerChannels...)
// Отправляем данные
go func() {
for i := 1; i <= 5; i++ {
input <- i
}
close(input)
}()
// Читаем результаты
for res := range results {
fmt.Printf("Результат: %d\n", res)
}
}

Ключевые моменты:

  • Fan-out: несколько горутин читают из одного канала, Go автоматически распределяет сообщения между ними.
  • Fan-in: используется sync.WaitGroup для ожидания завершения всех воркеров, после чего закрывается выходной канал.
  • Важно закрывать каналы корректно, чтобы избежать deadlock'ов.
  • Паттерн эффективен для параллельной обработки независимых задач, например, обработки запросов или вычислений.

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

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