以下是web application with golang 书里的笔记。
1.channels 和 Buffered Channels
- channels
channel是goroutine之间通信的一种机制。
定义方式如下:
ci := make(chan int)
cs := make(chan string)
- Buffered Channels
channel 还可以定义缓冲区大小,比如:
ci := make(chan int, 2)
- 存取数据
使用<-
来存入/获取数据,箭头方向代表数据的流向。
比如
向channel ci 写入数据:ci <- 10
从channel ci 获取数据并赋值到num:num := <- ci
2.Range和Close
channels里面的数据可以用range来读,但是这里有需要注意的地方:
1.记住应该在生产者的地方关闭channel,而不是消费的地方去关闭它,这样容易引起panic
2.另外记住一点的就是channel不像文件之类的,不需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束range循环之类的。如果没关闭,会报错:fatal error: all goroutines are asleep - deadlock!
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 1, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x + y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
3.Select
如果存在多个channel的时候,我们该如何操作呢,Go里面提供了一个关键字select,通过select可以监听channel上的数据流动。
select默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 1, 1
for {
select {
case c <- x:
x, y = y, x + y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
在select里面还有default语法,select其实就是类似switch的功能,default就是当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)。
有时候会出现goroutine阻塞的情况,那么我们如何避免整个程序进入阻塞的情况呢?我们可以利用select来设置超时,通过如下的方式实现:
func main() {
c := make(chan int)
o := make(chan bool)
go func() {
for {
select {
case v := <- c:
println(v)
case <- time.After(5 * time.Second):
println("timeout")
o <- true
break
}
}
}()
<- o
}
有疑问加站长微信联系(非本文作者)