Как работает небуферизированный канал в Go и в чем его особенность?

Ответ

Небуферизированный канал в Go — это канал с нулевой емкостью (make(chan T)), который обеспечивает синхронную передачу данных между горутинами.

Основная особенность заключается в том, что операция отправки и операция получения данных должны произойти одновременно. Это также называют «рандеву».

Принцип работы:

  1. Отправка (ch <- data) блокирует отправляющую горутину до тех пор, пока другая горутина не будет готова принять данные из этого же канала.
  2. Получение (<-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: готовлюсь получить данные...")
    value := <-ch // Разблокирует горутину-отправителя
    fmt.Printf("Main: получил данные: '%s'n", value)

    time.Sleep(1 * time.Second) // Даем время горутине завершиться
}

Ключевые моменты:

  • Синхронизация: Идеально подходит для синхронизации горутин, когда нужно гарантировать, что одно действие произошло перед другим.
  • Deadlock: Если горутина пытается отправить данные, но нет получателя (или наоборот), программа впадет в deadlock.