注:该系列文章全部来自 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设置超时来避免整个程序进入阻塞状态
代码版本一
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| 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") } }
|
最后程序的结果输出为:
1 2 3 4
| $ go run non-blocking-channel-operations.go no message received no message sent no activity
|
代码版本二
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package main import ( "fmt" ) func main() { messages := make(chan string, 1) signals := make(chan bool) select { case msg := <-messages: fmt.Println("received message", msg) default: fmt.Println("no message received") } 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", msg) case sig := <-signals: fmt.Println("received signal", sig) default: fmt.Println("no activity") } }
|
输出结果如下:
1 2 3 4
| $ go run non-blocking-channel-operations.go no message received sent message hi world received message hi world
|
代码版本三
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package main import ( "fmt" ) func main() { messages := make(chan string, 1) signals := make(chan bool) messages <- "test" select { case msg := <-messages: fmt.Println("received message", msg) default: fmt.Println("no message received") } 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", msg) case sig := <-signals: fmt.Println("received signal", sig) default: fmt.Println("no activity") } }
|
代码输出结果如下:
1 2 3 4
| $ go run non-blocking-channel-operations.go received message test sent message hi world received message hi world
|
代码版本四
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package main import ( "fmt" ) func main() { messages := make(chan string) signals := make(chan bool) messages <- "test" select { case msg := <-messages: fmt.Println("received message", msg) default: fmt.Println("no message received") } 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", msg) case sig := <-signals: fmt.Println("received signal", sig) default: fmt.Println("no activity") } }
|
代码输出结果为:
1
| fatal error: all goroutines are asleep - deadlock!
|
runtime goroutine
runtime包中有几个处理goroutine的函数
- Goexit - 退出当前执行的goroutine,但是defer函数还会继续调用
- Gosched - 让出当前goroutine的执行权限,调度器安排其它等待的任务运行,并在下次某个时候从该位置恢复执行
- NumCPU - 返回CPU核数量
- NumGoroutine - 返回正在执行和排队的任务总数
- GOMAXPROCS - 用来设置可以运行的CPU核数