Как узнать когда горутины закончили запись, чтобы закрыть канал?

В языке программирования Go каналы являются важным инструментом для обмена данными между горутинами. При работе с горутинами часто возникает необходимость определить момент, когда все горутины завершили свою работу, чтобы закрыть канал и сообщить об этом основной горутине.

Существует несколько подходов к решению этой задачи. Один из способов - использовать синхронизацию с помощью WaitGroup.

WaitGroup - это средство синхронизации, которое позволяет главной горутине ждать, пока все другие горутины завершат выполнение.

Вот пример кода, демонстрирующий этот подход:

package main

import (
	"fmt"
	"sync"
)

func worker(id int, wg *sync.WaitGroup, results chan<- int) {
	// Обозначает завершение работы горутины после выполнения
	defer wg.Done()

	// Выполняем некоторую работу
	result := id * 2

	// Отправляем результат в канал
	results <- result
}

func main() {
	// Создаем канал для получения результатов от горутин
	results := make(chan int)

	// Создаем WaitGroup
	var wg sync.WaitGroup

	// Запускаем горутины
	for i := 1; i <= 5; i++ {
		wg.Add(1)
		go worker(i, &wg, results)
	}

	// В этой горутине мы будем ждать, пока все горутины завершат работу
	go func() {
		wg.Wait()
		close(results)
	}()

	// Читаем результаты из канала
	for result := range results {
		fmt.Println(result)
	}
}

В этом примере мы создаем канал results для передачи результатов от горутин в основную горутину. Мы также создаем WaitGroup wg для синхронизации выполнения всех горутин.

В функции worker каждая горутина выполняет некоторую работу и отправляет свой результат в канал results. После завершения работы каждая горутина вызывает метод wg.Done(), чтобы сообщить WaitGroup о завершении работы.

В основной горутине мы запускаем все горутины и затем создаем отдельную горутину, которая будет ждать завершения работы всех горутин с помощью метода wg.Wait(). После того, как все горутины завершат работу, мы закрываем канал results.

Затем мы читаем результаты из канала results в цикле for result := range results и выводим их на экран. Этот цикл завершится, когда все значения будут прочитаны из канала после его закрытия.

Таким образом, использование WaitGroup позволяет определить момент, когда все горутины завершили свою работу, чтобы закрыть канал и завершить программу.