Ответ
Основное различие заключается в их поведении при отправке данных и, как следствие, в способе синхронизации горутин.
Небуферизированный канал: make(chan int)
- Синхронный: Обеспечивает прямое "рандеву" между отправителем и получателем.
- Блокировка при отправке: Операция отправки (
ch <- data
) блокирует горутину-отправителя до тех пор, пока другая горутина не будет готова принять данные из этого канала (<-ch
). - Блокировка при получении: Операция получения (
<-ch
) блокирует горутину-получателя до тех пор, пока другая горутина не отправит данные в этот канал. - Аналогия: Похоже на передачу эстафетной палочки — бегун не может отпустить палочку, пока следующий бегун её не возьмёт.
Буферизированный канал (размер 1): make(chan int, 1)
- Асинхронный: Отправитель и получатель могут работать независимо, пока буфер не заполнится или не опустеет.
- Блокировка при отправке: Отправка (
ch <- data
) блокируется, только если буфер уже заполнен. Если буфер пуст, отправитель помещает в него значение и немедленно продолжает выполнение, не дожидаясь получателя. - Блокировка при получении: Как и у небуферизированного, блокируется, если канал (его буфер) пуст.
Пример, демонстрирующий разницу:
package main
import "fmt"
func main() {
// Буферизированный канал размером 1
bufferedCh := make(chan int, 1)
bufferedCh <- 1 // Не блокируется, т.к. в буфере есть место
fmt.Println("Отправка в буферизированный канал не заблокировала выполнение")
// следующая отправка заблокирует, пока кто-то не прочитает
// bufferedCh <- 2
// Небуферизированный канал
unbufferedCh := make(chan int)
fmt.Println("Сейчас произойдет блокировка при отправке в небуферизированный канал...")
// Эта строка вызовет deadlock, если закомментировать горутину ниже,
// так как никто не готов принять данные.
go func() {
data := <-unbufferedCh
fmt.Printf("Данные [%d] получены из небуферизированного каналаn", data)
}()
unbufferedCh <- 100 // Блокируется, пока горутина выше не будет готова принять
fmt.Println("Отправка в небуферизированный канал успешно завершена")
}
Итог: Небуферизированный канал используется для гарантированной синхронизации двух горутин в определённой точке. Буферизированный канал используется для ослабления связи между отправителем и получателем, позволяя им работать с разной скоростью.