// Создаем канал для передачи целых чисел
ch := make(chan int)
// Создаем канал для передачи строк
strCh := make(chan string) ch <- 42 // Кладем число 42 в канал ch value := <-ch // Ждем, пока в канале что-то появится, и забираем это в переменную value package main
import (
"fmt"
"sync"
"time"
)
// Это наша функция-потребитель (Consumer)
// Она будет бесконечно читать данные из канала jobs и выводить их
func worker(jobs <-chan int, wg *sync.WaitGroup) {
// В конце сообщаем, что горутина завершилась
defer wg.Done()
// Цикл for...range по каналу — это идиоматичный способ читать из канала,
// пока он не будет закрыт.
for j := range jobs {
fmt.Println("Потребитель получил число:", j)
time.Sleep(500 * time.Millisecond) // Имитируем долгую обработку
}
fmt.Println("Канал закрыт, потребитель завершил работу.")
}
func main() {
// 1. Создаем канал для передачи "заданий" (чисел)
jobs := make(chan int)
// 2. Используем WaitGroup, чтобы main дождался завершения worker'а
var wg sync.WaitGroup
wg.Add(1) // У нас одна задача - дождаться worker'а
// 3. Запускаем горутину-потребителя
// Она сразу же заблокируется на строке `for j := range jobs`,
// так как канал jobs пока пуст.
go worker(jobs, &wg)
// 4. Теперь главная горутина (main) выступает в роли производителя (Producer)
fmt.Println("Производитель начинает отправлять числа...")
for i := 1; i <= 5; i++ {
fmt.Printf("Производитель отправляет число: %d\n", i)
jobs <- i // Отправляем число в канал.
// Эта операция заблокирует main, пока worker не заберет число.
}
// 5. ВАЖНО: Когда все задания отправлены, нужно закрыть канал.
// Это сигнал для потребителя, что больше данных не будет.
// Цикл `for...range` в worker'е увидит это и завершится.
close(jobs)
fmt.Println("Производитель отправил все числа и закрыл канал.")
// 6. Ждем, пока потребитель обработает все задания и завершится.
wg.Wait()
fmt.Println("Программа завершена.")
} package main
import (
"fmt"
"sync"
"time"
)
// Функция-потребитель (Consumer) остается без изменений
// Она все так же медленно обрабатывает задания
func worker(jobs <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for j := range jobs {
fmt.Printf(" Потребитель получил число: %d\n", j)
time.Sleep(500 * time.Millisecond) // Имитируем долгую обработку
}
fmt.Println(" Потребитель завершил работу.")
}
func main() {
// 1. Создаем БУФЕРИЗИРОВАННЫЙ канал с емкостью 5
jobs := make(chan int, 5)
var wg sync.WaitGroup
wg.Add(1)
go worker(jobs, &wg)
// 2. Главная горутина (Producer) теперь может отправлять числа,
// не дожидаясь, пока их заберет потребитель.
fmt.Println("Производитель начинает отправлять числа...")
for i := 1; i <= 5; i++ {
fmt.Printf("-> Производитель отправил число: %d\n", i)
jobs <- i // <- ЭТОТ ВЫЗОВ НЕ БЛОКИРУЕТСЯ!
// Main не ждет consumer'а, а сразу продолжает цикл.
}
// 3. После того как все числа отправлены в буфер, мы закрываем канал.
close(jobs)
fmt.Println("Производитель отправил все числа в буфер и закрыл канал.")
// 4. Ждем, пока потребитель обработает все задания из буфера.
wg.Wait()
fmt.Println("Программа завершена.")
} Производитель начинает отправлять числа...
-> Производитель отправил число: 1
-> Производитель отправил число: 2
-> Производитель отправил число: 3
-> Производитель отправил число: 4
-> Производитель отправил число: 5
Производитель отправил все числа в буфер и закрыл канал.
Потребитель получил число: 1
Потребитель получил число: 2
Потребитель получил число: 3
Потребитель получил число: 4
Потребитель получил число: 5
Потребитель завершил работу.
Программа завершена. value, ok := <-ch
if !ok {
fmt.Println("Канал закрыт, больше данных не будет.")
// здесь нужно выйти из цикла
} package main
import (
"fmt"
"sync"
"time"
)
// worker - это наша горутина-исполнитель.
// Она будет читать задания из канала jobs до тех пор, пока он не закроется.
func worker(id int, jobs <-chan int, wg *sync.WaitGroup) {
// Сообщаем, что горутина завершена, когда выйдем из функции
defer wg.Done()
fmt.Printf("Воркер #%d запущен и ждет заданий...\n", id)
// Идиоматичный цикл для чтения из канала.
// Он автоматически остановится, когда канал jobs будет закрыт.
for j := range jobs {
fmt.Printf("Воркер #%d взял в работу задание: %d\n", id, j)
time.Sleep(1 * time.Second) // Имитируем выполнение работы
fmt.Printf("Воркер #%d завершил задание: %d\n", id, j)
}
fmt.Printf("Воркер #%d завершил работу, так как канал заданий закрыт.\n", id)
}
func main() {
// 1. Создаем канал для передачи заданий
jobs := make(chan int)
// 2. Используем WaitGroup, чтобы main дождался завершения всех воркеров
var wg sync.WaitGroup
// 3. Запускаем 3 воркеров, которые будут конкурировать за задания из одного канала
for w := 1; w <= 3; w++ {
wg.Add(1) // Увеличиваем счетчик для каждого воркера
go worker(w, jobs, &wg)
}
// 4. Главная горутина (main) выступает в роли "диспетчера"
// и отправляет 5 заданий в канал
fmt.Println("Диспетчер начинает раздавать задания...")
for j := 1; j <= 5; j++ {
fmt.Printf("-> Диспетчер отправил задание: %d\n", j)
jobs <- j
}
// 5. ВАЖНО: После того как все задания отправлены, мы закрываем канал.
// Это сигнал для ВСЕХ воркеров, что новых заданий больше не будет,
// и они могут завершиться, как только закончат текущую работу.
close(jobs)
fmt.Println("Диспетчер отправил все задания и закрыл канал.")
// 6. Ждем, пока все воркеры завершат свою работу
wg.Wait()
fmt.Println("Все воркеры завершили работу. Программа завершена.")
} Диспетчер начинает раздавать задания...
-> Диспетчер отправил задание: 1
Воркер #1 запущен и ждет заданий...
Воркер #1 взял в работу задание: 1
-> Диспетчер отправил задание: 2
Воркер #2 запущен и ждет заданий...
Воркер #2 взял в работу задание: 2
-> Диспетчер отправил задание: 3
Воркер #3 запущен и ждет заданий...
Воркер #3 взял в работу задание: 3
-> Диспетчер отправил задание: 4
Воркер #1 взял в работу задание: 4
-> Диспетчер отправил задание: 5
Воркер #2 взял в работу задание: 5
Диспетчер отправил все задания и закрыл канал.
Воркер #1 завершил задание: 1
Воркер #1 завершил работу, так как канал заданий закрыт.
Воркер #3 завершил задание: 3
Воркер #3 завершил работу, так как канал заданий закрыт.
Воркер #2 завершил задание: 2
Воркер #2 завершил задание: 5
Воркер #2 завершил работу, так как канал заданий закрыт.
Все воркеры завершили работу. Программа завершена. package main
import (
"fmt"
"sync"
"time"
)
// worker - это наша функция-воркер.
// Она будет в бесконечном цикле читать задания из канала jobs
// и отправлять результаты в канал results.
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done() // Сообщаем, что этот воркер завершился
fmt.Printf("Воркер #%d запущен\n", id)
for j := range jobs {
fmt.Printf("Воркер #%d взял задание %d\n", id, j)
// Имитируем долгую работу
time.Sleep(time.Second)
// Отправляем результат (например, квадрат числа)
results <- j * j
fmt.Printf("Воркер #%d завершил задание %d\n", id, j)
}
}
func main() {
// 1. Создаем каналы для заданий и результатов
jobs := make(chan int, 10) // Буферизованный канал, чтобы не блокировать main
results := make(chan int, 10) // Буферизованный канал для результатов
// 2. Запускаем пул из 3 воркеров
var wg sync.WaitGroup
numWorkers := 3
for w := 1; w <= numWorkers; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// 3. Отправляем 5 заданий в канал jobs
numJobs := 5
for j := 1; j <= numJobs; j++ {
fmt.Printf("-> Отправляем задание %d\n", j)
jobs <- j
}
close(jobs) // ВАЖНО: закрываем канал, чтобы воркеры знали, что заданий больше не будет
fmt.Println("Все задания отправлены, канал jobs закрыт.")
// 4. Собираем результаты
// Мы знаем, что будет ровно numJobs результатов
for r := 1; r <= numJobs; r++ {
result := <-results
fmt.Printf("<- Получен результат: %d\n", result)
}
// 5. Ждем, пока все воркеры завершат свою работу (важно, если бы у них была логика после цикла)
wg.Wait()
fmt.Println("Все воркеры завершили работу.")
} package main
import (
"fmt"
"sync"
"time"
)
// Функция-воркер, которая просто отправляет числа в свой канал
func worker(id int, out chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
defer close(out) // Важно закрыть свой выходной канал, когда работа закончена
for i := 0; i < 3; i++ {
out <- id*10 + i // Воркер 1: 10, 11, 12. Воркер 2: 20, 21, 22.
}
}
// Функция, реализующая fan-in
func fanIn(inputChannels ...<-chan int) <-chan int {
var wg sync.WaitGroup
// Создаем общий выходной канал
output := make(chan int)
// Внутренняя функция для чтения из одного канала и отправки в общий
outputFunc := func(ch <-chan int) {
defer wg.Done()
for n := range ch {
output <- n
}
}
// Запускаем по горутине для каждого входного канала
wg.Add(len(inputChannels))
for _, ch := range inputChannels {
go outputFunc(ch)
}
// Отдельная горутина, которая ждет, пока все читающие горутины завершатся,
// и затем закрывает общий выходной канал.
go func() {
wg.Wait()
close(output)
}()
return output
}
func main() {
// 1. Fan-out: Запускаем двух воркеров
ch1 := make(chan int)
ch2 := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go worker(1, ch1, &wg)
go worker(2, ch2, &wg)
// 2. Fan-in: Собираем результаты из обоих каналов в один
combinedOutput := fanIn(ch1, ch2)
// 3. Читаем из общего канала, пока он не закроется
for n := range combinedOutput {
fmt.Println("Получено:", n)
}
// Ждем, пока воркеры не закроют свои каналы (хотя fan-in уже с этим справился)
wg.Wait()
fmt.Println("Работа завершена.")
}