Go内建channel实现了go协程之间数据的读写相关操作。
并发在Go当中不仅仅是语法。它是一种设计模式。该模式提供了在处理常见并发问题的解决方案。因为并发需要同步 。Go并发是源自CSP模型,通过channel来实现协程的同步。Go并发哲学是:不通过共享内存来通信,而是通过通信来共享内存。
1.创建一个channel
func main() {
c := make(chan int)
fmt.Println(len(c), " ", cap(c))
go func() {
for i := 0; i < 4; i++ {
c <- i
fmt.Println("正在接收", len(c), " ", cap(c))
}
close(c)
}()
for data := range c {//等同于num:=<-c,只不过一直迭代
fmt.Println(data)
}
}
如图便创建了一个容纳int类型的channel,可往中间存放int类型变量,当channel已经满,再写数据便会阻塞,channel为空,取数据依然阻塞,并且最后循环读取数据,没有数据就阻塞,用range来迭代不断操作channel。
如上图形象的解释了一个有缓冲的通道如何在goroutine之间同步数据。
第一步,右侧的goroutine正从通道接收一个值。
第二步,右侧的goroutine独立完成了接收值的动作,而左侧的goroutine正在发送一个新值到通道里。
第三步,左侧的goroutine还在向通道发送新值,而右侧的goroutine正在通道接收一个值,但是这两个操作既不是同步的,也不会互相阻塞。
第四步,所有发送与接收都已完成,而通道中还有几个值,也有一些空间可以存更多的值。
关闭channel
func main() {
//当channel已经满,再写数据便会阻塞,channel为空,取数据依然阻塞
c := make(chan int, 3) //当前带有缓冲的channel
fmt.Println(len(c), " ", cap(c))
go func() {
for i := 0; i < 4; i++ {
c <- i
fmt.Println("正在接收", len(c), " ", cap(c))
}
close(c) //防止一直读数据死锁
}()
for {
//ok为true表示没关闭,false已经关闭了
if data, ok := <-c; ok {
fmt.Println(data)
} else {
break
}
}
}
当channel关闭后可以从channel处收到数据,但是不能再写入数据了。
对于nil channel,无论读写都有问题。