GO并发(Goroutine),带缓冲信道和无缓冲信道(Channel), 多路复用(select),关闭信道(close)
信道
带缓冲信道代码
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
| package main
import ( "fmt" "time" )
func main() { ch := make(chan int, 2) over := make(chan bool) go func() { for i := 1; ; i++ { fmt.Println("开始", i) time.Sleep(time.Second * 2) fmt.Println("-------等待2秒---------") j, ok := <-ch if ok { fmt.Println("已接收", j) } else { fmt.Println("已全部接收") over <- true return } } }() for j := 1; j <= 3; j++ { ch <- j fmt.Println("发送", j) } close(ch) fmt.Println("已全部发送, 信道关闭") <-over }
|
带缓冲信道执行结果(发送等待5秒)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 开始 1 -------等待2秒--------- 发送 1 发送 2 发送 3 已全部发送, 信道关闭 已接收 1 开始 2 -------等待2秒--------- 已接收 2 开始 3 -------等待2秒--------- 已接收 3 开始 4 -------等待2秒--------- 已全部接收
|
带缓冲信道执行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 发送 1 发送 2 开始 1 -------等待2秒--------- 已接收 1 开始 2 发送 3 已全部发送, 信道关闭 -------等待2秒--------- 已接收 2 开始 3 -------等待2秒--------- 已接收 3 开始 4 -------等待2秒--------- 已全部接收
|
无缓冲信道执行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 开始 1 -------等待2秒--------- 已接收 1 开始 2 发送 1 -------等待2秒--------- 已接收 2 开始 3 发送 2 -------等待2秒--------- 已接收 3 开始 4 发送 3 已全部发送, 信道关闭 -------等待2秒--------- 已全部接收
|
多路复用
多路复用(select)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package main
import ( "fmt" "time" )
func main() { timeout := make (chan bool) go func() { time.Sleep(1e9) timeout <- true }() ch := make (chan int) select { case <- ch: case <- timeout: fmt.Println("timeout!") return } }
|
执行结果
select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行
default
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
| package main
import ( "fmt" "time" )
func main() { timeout := make (chan bool) go func() { time.Sleep(1e9) timeout <- true }() ch := make (chan int) for { select { case <- ch: case <- timeout: fmt.Println("timeout!") return default: fmt.Println("def") } } }
|
执行结果
当 select 中的其它分支都没有准备好时,default 分支就会执行。
close
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package main
import ( "fmt" )
func fibonacci(n int, c chan int) { for i := 0; i < n; i++ { c <- i } close(c) }
func main() { c := make(chan int, 10) go fibonacci(cap(c), c) for i := range c { fmt.Println(i) } }
|
循环 for i := range c
会不断从信道接收值,直到它被关闭。
执行结果