注:该系列文章全部来自 Go By Example 系列翻译而来,个人翻译水平以及理解水平有限,如要更加精确的理解,请看原文Go by Example: Non-Blocking Channel Operations。
在 channels (信道?) 上基本的 sends (发送) 和 receives (接收)是阻塞模式的。尽管如此, 我们可以使用 select 和一个 default 子句来非阻塞的 sends、receives,甚至是非阻塞的多路选择。
注:感谢@lidashuang的说明提醒,文章没有描述清楚,修改如下:select默认是阻塞的,但在select里面还有default语法,这类似于switch,default就是当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)
同时,有时候会出现goroutine阻塞的情况,可以利用select设置超时来避免整个程序进入阻塞状态
代码版本一
代码如下:
package main import "fmt" func main() { messages := make(chan string) signals := make(chan bool) /** 这里是一个非阻塞 receive。如果在 messages 上的值是可用的,那 select 将 <-messages 的值带上,执行 <-messages 下面的println语句。如果不是,它将立即带上 default 的值,执行 default 下面的println语句 **/ select { case msg := <-messages: fmt.Println("received message",msg) default: fmt.Println("no message received") } /** 一个非阻塞 send 的类似工作 **/ msg := "hi" select { case messages <- msg: fmt.Println("sent message",msg) default: fmt.Println("no message sent") } /** 我们可以用在 default 之上使用多个 cases 来实现一个非阻塞的多路 select。在这里我们尝试在 messages 和 signals 上实现非阻塞 receives。 **/ select { case msg := <-messages: fmt.Println("received message",msg) case sig := <-signals: fmt.Println("received signal",sig) default: fmt.Println("no activity") } }
最后程序的结果输出为:
$ go run non-blocking-channel-operations.go no message received no message sent no activity
代码版本二
代码如下:
package main import ( "fmt" ) func main() { // messages := make(chan string) //如果不加缓存的话,就全部会选择defalut messages := make(chan string,1) //加了缓存的话,会选择对应的 signals := make(chan bool) // messages <- "test" select { case msg := <-messages: fmt.Println("received message",msg) //因为messages目前本身还没有值,因此选择default执行 default: fmt.Println("no message received") } // go func() { msg := "hi world" // }() select { case messages <- msg: fmt.Println("sent message",msg) //因为channels有缓存,所以这里的msg发送到 channels messages 能处理,不会被阻塞住 default: fmt.Println("no message sent") } select { case msg := <-messages: fmt.Println("received message",msg) //因为messages已经有值了,所以会选择这个case执行 case sig := <-signals: fmt.Println("received signal",sig) default: fmt.Println("no activity") } }
输出结果如下:
$ go run non-blocking-channel-operations.go no message received sent message hi world received message hi world
代码版本三
代码如下:
package main import ( "fmt" ) func main() { // messages := make(chan string) //如果不加缓存的话,就全部会选择defalut messages := make(chan string,1) //加了缓存的话,会选择对应的 signals := make(chan bool) messages <- "test" select { case msg := <-messages: fmt.Println("received message",msg) //messages已经有值,因此选择这个case执行 default: fmt.Println("no message received") } // go func() { msg := "hi world" // }() select { case messages <- msg: fmt.Println("sent message",msg) default: fmt.Println("no message sent") } select { case msg := <-messages: fmt.Println("received message",sig) default: fmt.Println("no activity") } }
$ go run non-blocking-channel-operations.go received message test sent message hi world received message hi world
代码版本四
代码如下:
package main import ( "fmt" ) func main() { messages := make(chan string) //如果不加缓存的话,就全部会选择defalut //messages := make(chan string,1) //加了缓存的话,会选择对应的 signals := make(chan bool) messages <- "test" //因为该channels没有缓存,而其又赋值了,会到时死锁。 select { case msg := <-messages: fmt.Println("received message",msg) default: fmt.Println("no message received") } // go func() { msg := "hi world" // }() select { case messages <- msg: fmt.Println("sent message",sig) default: fmt.Println("no activity") } }
fatal error: all goroutines are asleep - deadlock!
runtime goroutine
runtime包中有几个处理goroutine的函数
原文链接:https://www.f2er.com/go/190971.html