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