Golang中的channel是不同goroutines之间进行通信和同步的桥梁,借助channel,可以很方便写多协程通信程序。
如何理解channel
Channel是一个协程安全的管道,一端写入数据,一端读取数据,写入和读取都是原子操作,有点类似于消息队列,只不过channel是内存级别的。在channel出现之前,需要手动管理共享内存,这样会带来一定的复杂度和不可知的问题。而channel提供了一种更简单、更安全的方式来进行并发编程,借助channel,可以在不共享内存的情况下实现多个goroutine之间的通信。
channel的基本操作
使用make()函数来创建一个channel示例,并且需要指定channel中元素的类型和容量(可选),例如:
ch := make(chan int) // 创建一个int类型的channel
这条创建语句没有指定容量,就是创建了一个无缓冲的channel,如果一个goroutine往这个channel发送数据,那么这个oroutine就会被阻塞住,直到有其它goroutine读取了channel 的数据才能继续运行。创建channel时如果指定了容量,就是有缓冲的channel,例如:
ch := make(chan int, 10) // 创建一个容量为10的int类型的channel
对于有缓冲的channel来说,只要当前channel里的元素总数不大于这个指定的容量,当前的goroutine就不会被阻塞住。
往channel写数据使用<-操作符,例如:
ch := make(chan int)
ch <- 1 //将值1发送到通道中
从channel读取数据也是使用<-操作符,例如:
val := <- ch //从通道中接收上一个发送的值
当不再使用channel时,使用close()方法关闭channel,例如:
close(ch)
当channel关闭后,如果继续往里面写数据,则会panic;如果继续读的话,不会产生panic,如果还有数据的话也可以读到数据,如果没有数据的话将得到零值(对应类型的默认值)。判断当前channel是否被关闭,可以使用下面的写法:
if v, ok := <-ch; !ok {
fmt.Println("channel已关闭并且数据已被读完")
}
也可以使用for range的方式,读取完数据后循环也随着结束,例如:
for v := range ch {
// ...
}