Ответ
Если при создании канала с помощью make(chan T)
не указать размер, создается небуферизованный (синхронный) канал. Его ключевое отличие — отсутствие внутреннего буфера для хранения значений.
Последствия и поведение небуферизованного канала:
Блокировка при отправке: Операция отправки в канал (
ch <- value
) заблокирует горутину-отправителя до тех пор, пока другая горутина не будет готова принять значение из этого канала.Блокировка при чтении: Операция чтения из канала (
value := <-ch
) заблокирует горутину-получателя до тех пор, пока другая горутина не отправит значение в этот канал.Синхронизация (Рандеву): Отправка и получение данных происходят одновременно. Это делает небуферизованные каналы мощным инструментом для синхронизации горутин, гарантируя, что одна горутина не продолжит выполнение, пока другая не достигнет определенной точки.
Пример:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string) // Небуферизованный канал
go func() {
fmt.Println("Горутина: готовлюсь отправить данные...")
ch <- "Привет!" // Эта строка заблокируется, пока main не будет готова читать
fmt.Println("Горутина: данные успешно отправлены.")
}()
fmt.Println("Main: жду 2 секунды перед чтением...")
time.Sleep(2 * time.Second)
fmt.Println("Main: готовлюсь прочитать данные...")
message := <-ch // Разблокирует горутину-отправителя
fmt.Printf("Main: получил сообщение: '%s'n", message)
}
Отличие от буферизованного канала
Буферизованный канал (make(chan T, N)
, где N > 0
) имеет внутренний буфер размером N
.
- Отправка в него не блокируется, пока в буфере есть свободное место.
- Чтение из него не блокируется, пока в буфере есть хотя бы один элемент.
Блокировка происходит только при попытке записи в переполненный буфер или чтения из пустого.