英文:
What is the benefit of sending to a channel by using select in Go?
问题
在Gorilla websocket的示例目录中,有一个名为hub.go的文件。
https://github.com/gorilla/websocket/blob/master/examples/chat/hub.go
在这里,你可以找到一个在hub类型上定义的方法,它实现了以下功能:
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)
}
}
}
}
}
为什么它不直接在最后一个case中像这样发送到c.send通道?
case m := <-h.broadcast:
for c := range h.connections {
c.send <- m
}
英文:
In the example directory of Gorilla websocket there is a file called hub.go.
https://github.com/gorilla/websocket/blob/master/examples/chat/hub.go
Here you can find a method on the type hub that does this.
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)
}
}
}
}
}
Why does it not just send to the c.send channel straight up in the last case like this?
case m := <-h.broadcast:
for c := range h.connections {
c.send <- m
}
答案1
得分: 6
这是一种保证非阻塞发送到通道的方法。
如果 c.send 通道当前无法接收新消息,将执行默认分支。
如果没有 select{} 块,发送到无缓冲或完全填满的缓冲通道可能会被阻塞。
英文:
It's method of guaranted nonblocking send to channel.
In case of c.send chan can't accept new messages now, a default branch will be executed.
Without select{} block sending to unbuffered or fully filled buffered channel can be blocked.
答案2
得分: 1
基本的通道发送和接收是阻塞的。然而,我们可以使用select
和default
子句来实现非阻塞的发送、接收,甚至是非阻塞的多路选择。
package main
import "fmt"
func main() {
messages := make(chan string)
//[...]
// 这是一个非阻塞的接收操作。如果`messages`通道中有值可用,
// `select`语句将选择`<-messages`这个`case`并接收该值。
// 如果没有可用值,它将立即选择`default`这个`case`。
select {
case msg := <-messages:
fmt.Println("接收到消息", msg)
default:
fmt.Println("未接收到消息")
}
// 非阻塞的发送操作类似。
msg := "hi"
select {
case messages <- msg:
fmt.Println("发送消息", msg)
default:
fmt.Println("未发送消息")
}
//[...]
}
更明确地说,对于非阻塞的“发送”操作,如果已经有接收方在等待消息,那么第一个case
将会执行。否则,它将回退到default
。
英文:
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")
}
//[...]
}
And to be more clear: for a non-blocking "send", the first case
will happen if there is a receiver already waiting for a message. Else it falls back to default
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论