go-channel笔记

Channel

Channel类型的定义格式如下:

ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .

它包括三种类型的定义。可选的<-代表channel的方向。如果没有指定方向,那么Channel就是双向的,既可以接收数据,也可以发送数据。

chan T          // 可以接收和发送类型为 T 的数据
chan<- float64 // 只可以用来发送 float64 类型的数据
<-chan int // 只可以用来接收 int 类型的数据

使用make初始化Channel,并且可以设置容量:

ch := make(chan int, 100)

容量(capacity)代表Channel容纳的最多的元素的数量,代表Channel的缓存的大小。
如果没有设置容量,或者容量设置为0, 说明Channel没有缓存,只有sender和receiver都准备好了后它们的通讯(communication)才会发生(Blocking)。如果设置了缓存,就有可能不发生阻塞, 只有buffer满了后 send才会阻塞, 而只有缓存空了后receive才会阻塞。一个nil channel不会通信。

加上defer防止panic之后进程退出

package main
import (
"fmt"
"log"
"time"
)
func main() {
ch := make(chan int, 10)
defer close(ch)
for i := 0; i < 2; i++ {
go worker(ch, i)
}
for i := 0; i < 3; i++ {
ch <- i
ch <- -1
}
time.Sleep(time.Second * 5)
}
func worker(ch <-chan int, goId int) {
defer func(ch <-chan int) {
if err := recover(); err != nil {
log.Printf("worker%d recover error:%s", goId, err)
go worker(ch, goId)
}
}(ch)
log.Printf("worker%d running", goId)
for data := range ch {
log.Printf("worker%d received data:%d", goId, data)
if data == -1 {
panic(fmt.Errorf("worker%d panic", goId))
}
}
}

往一个已经被close的channel中继续发送数据会导致run-time panic。
往nil channel中发送数据会一致被阻塞着。

receive 操作符

<-ch用来从channel ch中接收数据,这个表达式会一直被block,直到有数据可以接收。
从一个nil channel中接收数据会一直被block。
从一个被close的channel中接收数据不会被阻塞,而是立即返回,接收完已发送的数据后会返回元素类型的零值(zero value)。
你可以使用一个额外的返回参数来检查channel是否关闭。

x, ok := <-ch
x, ok = <-ch
var x, ok = <-ch

如果OK 是false,表明接收的x是产生的零值,这个channel被关闭了或者为空。

发送操作符

如果channel c已经被关闭,继续往它发送数据会导致panic: send on closed channel:

blocking

缺省情况下,发送和接收会一直阻塞着,直到另一方准备好。这种方式可以用来在gororutine中进行同步,而不必使用显示的锁或者条件变量。

for …… range语句可以处理Channel。