go 的并发编程采用的 CSP (Communicating Sequential Process) 模型,主要基于协程 goroutine 和通道 channel .


2.1 协程 go

在 go 语言中,并发编程使用关键字 go 即可快速启动一个并发运行的 goroutine. 如下:

go 函数名 (参数列表)
go f(a int, b int, c int){
  fmt.Println(a+b+c)
}(1,2,3)


2.2 channel 通道

golang 提供了通道类型 chan,用于在并发操作时的通信,它本身就是并发安全的. 通过 chan 可以创建无缓冲、缓冲通道,满足不同需求. 写法如下:

make(chan int)
make(chan int, 10)
<- chan
chan <-

无缓冲通道: 要求接受和发送数据的 goroutine 同时准备好,否则将会阻塞.

有缓冲通道: 给予通道一个容量值,只要有值便可以接受数据,有空间便可以发送数据,可以不阻塞的完成.

单向通道: 默认情况通道是双向的,可以接受及发送数据. 也可以创建单向通道,只能收或者发数据. 如下是单向接受通道

var ch chan<- float64


2.3 select

select: 可以监听 channel 上的输入/输出操作, 类似于 select、epoll、poll 使得通道支持多路复用. select 是专门通道 channel 设计的. 它可以结合通道实现超时处理、判断缓冲通道是否阻塞、退出信号量处理,如下:

// 1. 超时机制
select {
case <-ch:
case <-timeout:
fmt.Println("timeout 01")
}


// 2. 退出信号量处理
select {
    case <- quitChan:
return
default:
}


// 3. 判断缓冲通道是否已满
ch := make(chan int, 5)
ch <- 1
select {
case ch <- 2:
        fmt.Println("channel value is", <-ch)
default:
fmt.Println("channel blocking")
}



2.4 内置函数 close()
close() 函数用于关闭通道 channel 的,close 之后的 channel 还可以读取数据,close() 函数由以下几点使用要点:

  1. 只能关闭双向通道或者发送通道

  2. 它应该由发送者使用,而不应该由接受者调用

  3. 当通道关闭后,接受者都不再阻塞,

  4. 关闭通道后,依然可以从通道中读取值

  5. 所有元素读取完后,将返回通道元素的零值,并且读取检测值也是 false 


示例:

ch := make(chan int, 1)
ch <- 3
close(ch) // 关闭ch
v, ok := <- ch 3,true
v2,ok := <- ch // 0,false