Kanały niebuforowane
Synchroniczne przekazywanie danych między goroutines
Kanały niebuforowane to bezpłatna lekcja Go Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Go Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Go Academy zawiera 4 lekcji w sumie.
Czym jest kanał?
Kanał to typowany mechanizm komunikacji między gorutynami. Kanały realizują zasadę Go: Nie komunikuj się przez współdzielenie pamięci; współdziel pamięć przez komunikację.
package main
import "fmt"
func main() {
ch := make(chan int) // unbuffered int channel
go func() {
ch <- 42 // send: blocks until someone receives
}()
v := <-ch // receive: blocks until someone sends
fmt.Println(v) // 42
}Semantyka kanału niebuforowanego
Kanał niebuforowany nie ma pojemności. Wysyłanie blokuje się, dopóki odbiorca nie będzie gotowy, a odbiór blokuje się, dopóki nadawca nie wyśle wartości. Zapewnia to gwarantowane synchroniczne przekazanie:
package main
import "fmt"
func double(in <-chan int, out chan<- int) {
for v := range in {
out <- v * 2
}
close(out)
}
func main() {
in := make(chan int)
out := make(chan int)
go double(in, out)
go func() { in <- 3; in <- 5; close(in) }()
for v := range out { fmt.Println(v) }
// 6
// 10
}Kanał jako mechanizm synchronizacji
Kanały niebuforowane synchronizują gorutyny — należy używać ich jako sygnału zakończenia pracy:
package main
import "fmt"
func compute(result chan<- int) {
sum := 0
for i := 1; i <= 100; i++ { sum += i }
result <- sum
}
func main() {
ch := make(chan int)
go compute(ch)
fmt.Println("Result:", <-ch) // blocks until compute sends
}Zamykanie kanału
Nadawca zamyka kanał za pomocą close(ch), aby zasygnalizować, że nie zostaną wysłane żadne kolejne wartości. Odbiorcy wykrywają zamknięcie za pomocą postaci z dwiema wartościami:
package main
import "fmt"
func generate(ch chan<- int, max int) {
for i := 0; i < max; i++ {
ch <- i
}
close(ch) // signal done
}
func main() {
ch := make(chan int)
go generate(ch, 5)
for v := range ch { // range detects close automatically
fmt.Println(v)
}
fmt.Println("channel closed")
}Odbiór dwóch wartości
Odbiór dwóch wartości v, ok := <-ch informuje, czy kanał jest nadal otwarty:
package main
import "fmt"
func main() {
ch := make(chan string, 1)
ch <- "hello"
close(ch)
v1, ok1 := <-ch
fmt.Println(v1, ok1) // hello true
v2, ok2 := <-ch
fmt.Println(v2, ok2) // "" false — channel closed
}Wysyłanie do zamkniętego kanału wywołuje panikę
Wysłanie wartości do zamkniętego kanału wywołuje panikę. Tylko nadawca powinien zamykać kanał — nigdy odbiorca:
package main
import "fmt"
func main() {
ch := make(chan int)
close(ch)
// Receiving from closed channel returns zero value
v, ok := <-ch
fmt.Println(v, ok) // 0 false
// Sending to closed channel panics:
defer func() { recover() }()
ch <- 1 // panic: send on closed channel
}Kanały kierunkowe
Dla większej przejrzystości i bezpieczeństwa można ograniczyć kanały w sygnaturach funkcji do kanałów tylko do wysyłania (chan<- T) lub tylko do odbierania (<-chan T):
package main
import "fmt"
func producer(out chan<- int) { // send-only
for i := 0; i < 3; i++ { out <- i }
close(out)
}
func consumer(in <-chan int) { // receive-only
for v := range in { fmt.Println(v) }
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}Ping-pong gorutyn i kanałów
Dwie gorutyny przekazujące sobie wiadomość za pośrednictwem kanałów — klasyczny przykład synchronizacji:
package main
import "fmt"
func ping(ping, pong chan struct{}) {
for i := 0; i < 3; i++ {
<-ping
fmt.Println("ping")
pong <- struct{}{}
}
}
func main() {
ping := make(chan struct{})
pong := make(chan struct{})
go func() { for { <-pong; fmt.Println("pong"); ping <- struct{}{} } }()
go func() { for i := 0; i < 3; i++ { ping <- struct{}{}; <-pong } }()
// Simplified version:
fmt.Println("channels enable structured communication")
}Kanały nil blokują na zawsze
Odbieranie z kanału nil lub wysyłanie do niego blokuje na zawsze. Czasami wykorzystuje się to celowo w instrukcjach select:
package main
import "fmt"
func main() {
var ch chan int // nil channel
fmt.Println(ch == nil) // true
// select with nil channel — that case is never selected
active := make(chan int, 1)
active <- 42
select {
case v := <-ch: // never selected (nil)
fmt.Println(v)
case v := <-active: // selected
fmt.Println("got:", v)
}
}Kiedy używać kanałów niebuforowanych
Kanałów niebuforowanych należy używać, gdy:
- Potrzebne jest gwarantowane synchroniczne przekazanie
- Gorutyna musi potwierdzić odbiór, zanim nadawca będzie kontynuować działanie
- Implementowane są semafory lub mechanizm back-pressure
- Tworzone są potoki, w których każdy etap powinien przetwarzać jeden element naraz
Szybki test
Co się dzieje, gdy nastąpi próba wysłania do niebuforowanego kanału, gdy żaden odbiorca nie jest gotowy?
Podsumowanie: kanały niebuforowane
Podsumowanie:
- Tworzenie za pomocą
make(chan T)— zerowa pojemność - Wysyłanie blokuje się do chwili gotowości odbiorcy, a odbiór — do chwili wysłania wartości przez nadawcę
- Tylko nadawca powinien zamykać kanał
range chiteruje do zamknięcia kanału- Odbiór dwóch wartości:
v, ok := <-ch - Dla większej przejrzystości należy używać typów kierunkowych:
chan<-i<-chan
Często zadawane pytania
Czy lekcja „Kanały niebuforowane” jest bezpłatna?
Tak — pełny tekst „Kanały niebuforowane” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Go Academy, przejdź na CoddyKit PRO. Kurs Go Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Kanały niebuforowane”?
Synchroniczne przekazywanie danych między goroutines Ćwiczysz Go Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Go Academy?
Nie wymagamy żadnego doświadczenia. Go Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Kanały niebuforowane”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Go Academy?
Tak. Każda lekcja Go Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Uruchamianie goroutines
- Kanały niebuforowane
- Kanały buforowane
- Kierunek kanałów i wzorce potoków