Ответ
Да, при создании канала можно не указывать его размер. Такой канал называется небуферизированным (или синхронным).
// Небуферизированный канал
ch := make(chan int)
// Буферизированный канал размером 5
// bufferedCh := make(chan int, 5)
Принцип работы небуферизированного канала:
Он работает по принципу рандеву. Это означает, что операция отправки и операция получения данных должны произойти одновременно.
- Горутина, отправляющая данные (
ch <- data
), будет заблокирована до тех пор, пока другая горутина не будет готова принять эти данные (<-ch
). - И наоборот, горутина, читающая данные, будет заблокирована, пока другая горутина не отправит в него данные.
Это делает небуферизированные каналы идеальным инструментом для синхронизации двух горутин.
Пример синхронизации:
package main
import (
"fmt"
"time"
)
func main() {
done := make(chan bool) // Небуферизированный канал для сигнала
go func() {
fmt.Println("Рабочая горутина начала работу...")
time.Sleep(2 * time.Second)
fmt.Println("Рабочая горутина закончила работу.")
done <- true // Отправляем сигнал о завершении. Блокируемся, пока main не прочитает.
}()
// Основная горутина блокируется здесь, ожидая сигнала из канала done.
<-done
fmt.Println("Основная горутина получила сигнал и завершается.")
}
Ключевое отличие от буферизированного канала:
Буферизированный канал (make(chan int, N)
) имеет внутренний буфер. Отправляющая горутина блокируется только тогда, когда буфер полон. Читающая горутина блокируется только тогда, когда буфер пуст. Это позволяет осуществлять асинхронную коммуникацию без немедленной синхронизации.