Go语言的并发模型以其简练而独特的设计、对开发者的简洁易用以及高性能而区分于其他的传统开发语言,如C++、Java等。Go语言提供了围绕着Goroutine、Channel为核心概念的并发特性,正确地理解和使用它们,不仅可以避免程序出现一些并发或同步方面难以预知的运行问题,也有助于开发者更优雅地设计出利用Go并发模式的模块及系统。
本文主要针对Go并发模型下的Channel的使用,结合实际开发中的体会做一下总结,希望借此帮助接触Go语言不久的开发者们,正确掌握Channel这一重要并发特性的打开方式,并在实际项目中自如地使用Go语言的并发特性,开发出正确而高效的程序。
Channel概述
开始学习Go的同学们一定都知道Channel了,这可以说是Go语言提供的最亮眼的一个语言特性了。顾名思义,Channel即通道,是Go语言中用来在不同Goroutine之间进行通讯的管道。Go语言中的各种类型,从原生类型Int、 Int64、 String、Map等,到Struct、Interface、Pointer,都可以用Channel来在各个Gouroutine之间传递。
Channel的声明和初始化非常简单,同时需要指定Channel中所传递的数据的类型:
var ch1 chan interface{} //声明一个传递类型为interface{}的channel ch2 := make(chan int) //创建一个传递的数据类型为int的unbuffered channel ch3 := make(chan string, 5) //创建一个传递string类型的buffered channel, buffer的容量为5
这里要注意的是,已声明但是没有初始化的Channel,它的值是nil, nil的Channel无论发送和读取都会阻塞。后面的章节会列出几种使用Channel时的坑,并一一说明。
往Channel中写入及读取:
ch1 <- x //往Channel中写入值 y = <- ch2 //从channel中取出值 <- ch3 //取值并丢弃 close(ch3) //关闭channel
以上是Channel的定义和基本使用方式,Golang官方以及中文社区都有大量的资料说明。在这里要展开深入讨论的是Channel的正确打开方式。因为仅仅了解了Channel怎样定义,怎样写入和读取,仍然不足以让你写出正确使用Channel的Go语言程序。下面一部分,我们会从Channel的使用细节和实例,来看看它的正确打开方式是怎样的,在实际使用中有哪些坑需要注意。