Найти тему

#11 Паттерн fan-out/fan-in в Go

Паттерн fan-out/fan-in используется для распараллеливания и координации задач (горутин). Особенно полезен, когда одну трудоемкую задача можно разделить на более мелкие подзадачи.

Cостоит из двух стадий:

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

2. Fan-in: результаты всех одновременно выполняемых подзадач собираются и объединяются в единый результат.

fan-out / fan-in
fan-out / fan-in

Реализация на Go

Используем комбинацию горутин и каналов в Go. Каждая подзадача назначается горутине, а каналы передают данные между горутинами. Стадия fan-in ожидает завершения всех подзадач, координируя их с помощью примитивов синхронизации, таких как sync.WaitGroup, или используя канал с сигналом о завершении каждой подзадачи.

Пример 1

"Тяжелую" задачу по вычислению факториала разбиваем на несколько подзадач. Для этого:

1. Создаем канал results в него будем записывать результаты вычислений.

2. Для каждого числа из списка nums запускаем горутину, которая вычисляет факториал и отправляет результат в канал out. Это "fan-out".

3. Запускаем горутину, которая ждёт завершения всех "вычислительных" горутин, используя sync.WaitGroup и затем закрывает канал out.

4. В главной горутине читаем результаты из канала out и выводим их.

факториал
факториал

ссылка на Playground

Пример 2

Рассмотрим пример поинтереснее, когда у нас несколько воркеров. Подзадачей будет вычисление куба числа.

1. Определяем количество подзадач (numJobs) и воркеров (numWorkers), которые будут выполнять эти задачи.

2. Создаем два канала: один для подзадач (jobs), второй для результатов (results). Оба буферизованы с размером, равным количеству подзадач, чтобы можно было записывать в них, не блокируясь.

3. В цикле наполняем jobs подзадачами.

4. Запускаем воркер-горутины, которые будут обрабатывать подзадачи из канала jobs и отправлять результаты в канал results.

5. После того как все задачи отправлены, канал jobs закрываем - это сигнализирует воркерам, что больше задач не будет.

6. Запускаем горутину, которая ждет, пока счетчик WaitGroup не достигнет нуля, после чего закрываем канал results.

7. В главной горутине читаем результаты из канала results и выводим их. По мере чтения каждого результата, счетчик WaitGroup уменьшается.

куб числа
куб числа

ссылка на Playground

В следующих статьях рассмотрим примеры таких задач, которые дают на собеседованиях.