Golang-Channel能怎么用?


Golang CSP

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

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

channel初始化

使用channel必须make初始化。

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

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

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主要用在函数声明中。是约定,但是强制必须这样。

// 输入一个只能写的channel,返回一个只能读的channel
func foo(ch chan<- int) <-chan int {...}

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

channel读写

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编译有关。

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 内部数据读完之后循环自动结束。

for x := range ch {
    fmt.Println(x)
    ...
}

channel关闭

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/


  目录