Golang-Channel能怎么用?


Golang CSP

不要通过共享内存来通信,而应该通过通信来共享内存。

CSP模型用于描述两个独立的并发实体通过共享的通信管道(channel)进行通信的并发模型。Golang借用process和channel两个概念作为并发的理论支持。process在golang表现就是goroutine是实际并发执行的实体,每个实体之间通过channel通信实现数据共享。

channel初始化

使用channel必须make初始化。

1
2
unBufferChan := make(chan Type, 0) // Type: int、string...
bufferChan := make(chan Type, N) // 有缓存的通道

如果使用未初始化的channel会有dead lock错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
var x chan int
go func() {
x <- 1
}()
<-x
}

--------

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive (nil chan)]:
main.main()

单向channel

单向channel主要用在函数声明中。是约定,但是强制必须这样。

1
2
3
4
5
6
7
// 输入一个只能写的channel,返回一个只能读的channel
func foo(ch chan<- int) <-chan int {...}

// context包的Done()方法。
func (c *Context) Done() <-chan struct{} {
return nil
}

channel读写

1
2
3
4
5
6
7
ch := make(chan int, 10)

// 读操作
x <- ch

// 写操作
ch <- x
    1. 从空的缓冲channel里读消息,会block。
    2. 从无缓冲channel读消息,如果没有另一个goroutine正在写,会block。
    3. 从已关闭的channel读消息,==v,ok := <-c==,v为通道类型的默认值,ok为false。
    1. 向无缓冲channel写消息,如果没有另一个goroutine正在读,会block。
    2. 向已关闭的channel写消息,会panic。==panic: send on closed channel==。

select

select内channel有点特殊,不会block,与golang编译有关。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
select {
case e, ok := <-ch1:
...
case e, ok := <-ch2:
...
default:
}

for {
select {
...
}
}

// 超时控制
select {
case <- ch:
// get data from ch
case <- time.After(2 * time.Second)
// read data from ch timeout
}

range

一旦 channel 关闭,channel 内部数据读完之后循环自动结束。

1
2
3
4
for x := range ch {
fmt.Println(x)
...
}

channel关闭

1
2
3
4
ch := make(chan int)

// 关闭
close(ch)
    1. 重复关闭channel,会panic。==panic: close of closed channel==。

参考

https://www.jianshu.com/p/36e246c6153d

http://legendtkl.com/2017/07/30/understanding-golang-channel/


  目录