Bài học theo mô-đun (2/5)
Kênh: giao tiếp đánh máy
Kênh là cơ chế đặc trưng để giao tiếp giữa goroutine. Triết lý cờ vây (Rob Pike):
"Đừng giao tiếp bằng cách chia sẻ bộ nhớ; hãy chia sẻ bộ nhớ bằng cách giao tiếp."
Kênh là hàng đợi FIFO được nhập, loại an toàn và an toàn cho hoạt động đồng thời
sử dụng. Kết hợp với go, đây là khối xây dựng chính của cờ vây
sự đồng thời.
Tạo, gửi, nhận
ch := make(chan int) // canale di int, unbuffered
go func() {
ch <- 42 // invia (può bloccare)
}()
v := <-ch // ricevi (può bloccare)
fmt.Println(v) // 42Cú pháp:
make(chan T)hoặcmake(chan T, N)để lưu vào bộ đệm.ch <- vgửi.v := <-chnhận được.v, ok := <-chnhận được có gắn cờ (ok = falsenếu kênh bị đóng VÀ trống).
Không có bộ đệm: điểm hẹn
Khối kênh không có bộ đệm (dung lượng 0):
- người gửi cho đến khi người nhận sẵn sàng;
- người nhận cho đến khi người gửi sẵn sàng.
Đó là cuộc hẹn đồng bộ: hữu ích như một “tín hiệu” hoặc để đảm bảo rằng giá trị đã được chuyển giao.
Được đệm: xếp hàng lên tới N
ch := make(chan int, 3)
ch <- 1 // non blocca
ch <- 2 // non blocca
ch <- 3 // non blocca
ch <- 4 // BLOCCA: il buffer è pienoNgười gửi chỉ chặn khi bộ đệm đầy; chỉ người nhận khi nó trống rỗng.
gần và tầm xa
người gửi đóng kênh khi không còn giá trị nào:
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for v := range ch { // termina quando ch è chiuso E vuoto
fmt.Println(v)
}for range lặp lại trên một kênh cho đến khi kênh bị đóng (và cạn kiệt).
Đây là mẫu rõ ràng nhất để "tiêu thụ mọi thứ đến".
Tính định hướng trong chữ ký
Các tham số chức năng có thể hạn chế hướng:
func producer(out chan<- int) { // solo invio
out <- 1
close(out)
}
func consumer(in <-chan int) { // solo ricezione
for v := range in {
fmt.Println(v)
}
}chan<- T = chỉ gửi, <-chan T = chỉ nhận. Hai chiều
kênh chan T có thể được chuyển sang một trong hai kênh (chuyển đổi ngầm). Nó
cải thiện sự rõ ràng và ngăn ngừa sai lầm.
Các mẫu phổ biến (xem trước)
- Nhóm công nhân: N goroutine tiêu thụ từ
jobs <-chan T, sản xuất vàoresults chan<- R. - Đường ống: các giai đoạn được kết nối bằng kênh.
- Tín hiệu hoàn tất: kênh
chan struct{}đóng để báo hiệu "dừng".
done := make(chan struct{})
go func() {
<-done // blocca finché qualcuno chiude done
cleanup()
}()
close(done) // segnale di stopchan struct{} là kênh "tín hiệu": tải trọng bằng 0 byte, chỉ
đồng bộ hóa.
Hãy thử nó
Tạo một kênh int không có bộ đệm, gửi 42 từ goroutine, nhận vào main và in nó.
Hiển thị gợi ý
Không có bộ đệm, người gửi và người nhận sẽ đồng bộ hóa.
Giải pháp khả dụng sau 3 lần thử
Gửi 1,2,3 qua kênh đệm, đóng nó, sau đó in mọi thứ bằng for-range.
Hiển thị gợi ý
`cho phạm vi` trên một kênh kết thúc khi kênh bị đóng và cạn kiệt.
Giải pháp khả dụng sau 3 lần thử
Kênh UNBUFFERED sẽ làm gì khi người gửi gửi nhưng chưa có người nhận nào sẵn sàng?
ch := make(chan int)
ch <- 1 // ?Tóm tắt lại
- Channel = gõ hàng đợi FIFO, an toàn giữa các goroutines.
- Unbuffered: rendezvous (đồng bộ người gửi và người nhận).
- Buffered: tách rời, chỉ chặn khi đầy/trống.
close(ch): chỉ người gửi;for rangetiêu thụ cho đến khi đóng.- Tính định hướng:
chan<- T(chỉ gửi),<-chan T(chỉ nhận). chan struct{}làm kênh tín hiệu để đồng bộ hóa thuần túy.