Go的两种并发模式
- goroutine 和通道(channel)实现的通信顺序进程(CSP)模式
- 共享内存多线程模式
goroutine和通道
goroutine
goroutine指每一个并发执行的活动。main函数在主goroutine中执行。goroutine通过go关键字创建。
go f() // 新建一个goroutine调用f(),go语句本身立即返回
main函数返回时,所有goroutine直接终结,程序退出。除此之外,一个goroutine不能直接停止另一个goroutine,但可以发信号通知它自己停止。
通道
goroutine之间通过通道发送数据。通道是一个有具体类型(称作元素类型)的导管,比如元素类型为int的通道写作 chan int。
创建通道
ch = make(chan int) // 创建通道,ch 的类型是 chan int,为引用类型
通道操作
ch <- 3 // 发送3
x = <-ch // 接受,x=3
ch <- 5 // 发送5
close(ch) // 关闭通道,关闭后的发送会导致宕机,多次关闭也会宕机
x = <-ch // 关闭后继续接受已发送的值,x=5
x = <-ch // 通道为空且已关闭,每次接受都立即返回对应类型的零值
x, ok := <-ch // 返回通道元素和一个布尔值,false表示关闭且读完
缓冲
ch = make(chan int) // 无缓冲通道
ch = make(chan int, 0) // 无缓冲通道
ch = make(chan int, 3) // 缓冲为3的通道
cap(ch) // 获取缓冲区容量
len(ch) // 获取通道内元素个数
无缓冲通道
先执行发送会阻塞,直到另一个goroutine接受。
先执行接受也会阻塞,直到另一个goroutine发送。
也称为同步通道
缓冲通道
通道满了,再发送会阻塞
通道内无元素时,再接受会阻塞
管道(pipeline)
通道连接goroutine,一个的输入是另一个的输出,称作管道。
单向通道
ch := make(chan int, 1)
var in <-chan int = ch // 只能从in接受数据
var out chan<- int = ch // 只能发送数据到out
out <- 10
i := <-in
select 多路复用
和switch类似,有多个情况和一个default分支,每个情况指定一次通信(在通道上发送或接收)和关联的代码块。若多个情况都可以执行,随机选择一个,若都不能执行,则执行default,没有default则select将一直阻塞。
ch := make(chan int, 2)
for {
select {
case <-ch:
println("receive A")
case <-ch:
println("receive B")
case i := <-ch:
println("receive", i)
case ch <- 5:
println("send 5")
default:
println("default")
}
}
输出:
send 5
send 5
receive A
receive B
send 5
send 5
receive B
receive B
send 5
receive 5
send 5
……