В чем преимущество отправки на канал с помощью select in Go?
В каталоге примеров веб-сокета Gorilla есть файл с именем hub.go.
https://github.com/gorilla/websocket/blob/master/examples/chat/hub.go
Здесь вы можете найти метод на концентраторе типов, который делает это.
func (h *hub) run() {
for {
select {
case c := <-h.register:
h.connections[c] = true
case c := <-h.unregister:
if _, ok := h.connections[c]; ok {
delete(h.connections, c)
close(c.send)
}
case m := <-h.broadcast:
for c := range h.connections {
select {
case c.send <- m:
default:
close(c.send)
delete(h.connections, c)
}
}
}
}
}
Почему он не просто отправляет канал c.send прямо в последнем случае, как это?
case m := <-h.broadcast:
for c := range h.connections {
c.send <- m
}
2 ответа
Это метод гарантированной неблокирующей отправки на канал. В случае c.send chan не может принимать новые сообщения сейчас, будет выполнена ветка по умолчанию. Без выбора блока {} блокировка отправки на небуферизованный или полностью заполненный буферизованный канал может быть заблокирована.
https://gobyexample.com/non-blocking-channel-operations
// Basic sends and receives on channels are blocking.
// However, we can use `select` with a `default` clause to
// implement _non-blocking_ sends, receives, and even
// non-blocking multi-way `select`s.
package main
import "fmt"
func main() {
messages := make(chan string)
//[...]
// Here's a non-blocking receive. If a value is
// available on `messages` then `select` will take
// the `<-messages` `case` with that value. If not
// it will immediately take the `default` case.
select {
case msg := <-messages:
fmt.Println("received message", msg)
default:
fmt.Println("no message received")
}
// A non-blocking send works similarly.
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message sent")
}
//[...]
}
И чтобы быть более понятным: для неблокирующего "отправить", первый case
произойдет, если получатель уже ожидает сообщения. Иначе это возвращается к default