上述通过 net 包实现的网络通信看上去非常复杂,别急,GoLang 提供了更为好用的连接 goroutine 的工具 -- 通道

通道实现了一个 goroutine 发送特定值到另一个 goroutine 的通信机制,它与 unix 环境中的管道非常类似

此前,我们已经介绍过 unix 环境中的管道的使用,他是 unix 环境下最为常用的进程间通信方式:

 

通道的类型

通道的类型就是 chan xxx,其中 xxx 可以是任何类型名,例如:

chan int

chan struct{}

 

上述这样类型的通道既可以用来发送也可以用来接收数据

同样,我们也可以声明只用于发送或接收的单向通道:

chan<- int -- 只用于发送的通道

<-chan int -- 只用于接收的通道

 

通道的创建和关闭

通道的创建

和 map 一样,通道通过内置函数 make 就可以实现创建:

 

 

make 的第二个参数是可选的,用来表示创建的缓冲区大小,默认表示无缓冲区

如果缓冲区已满或没有缓冲区,那么在通道上的发送操作会被阻塞,直到另一个 goroutine 在该通道上接收数据或者发送操作被中止

同样,当缓冲区为空或没有缓冲区,接收操作也会被阻塞,直到由发送方发送新的数据

 

特别的,有时我们并不想通过通道传递任何数据,只是想要通过通道发送一个信号,此时,我们通常使用 chan struct{} 类型的通道,传递一个 struct{}{} 空对象

 

通道的关闭

内置函数同样提供了关闭通道的方法:

 

 

在通道关闭后,任何发送操作都会产生宕机,而接收操作会读取通道中所有剩余数据

如果在通道关闭后,所有数据已经被接收,再次执行接收操作会立即返回对应类型的零值

 

在 GoLang 中,如果在使用文件后没有执行 close 操作,将会造成无法回收的内存泄漏,但对于通道来说不会,垃圾回收器会根据通道是否可以被访问来决定是否回收相应的资源,无论通道是否进行过 close 操作

 

通道的发送和接收

 

 

示例

双向通道

有了通道,我们上面通过 TCP 实现通信的例子就可以十分简化了:

 

 

打印出了:

server recieved: Client say hello

client recieved: Server say world

 

这个例子展示了通过 chan struct{} 类型的通道报告 goroutine 运行结束的机制,这是非常常用的一种方法

 

单向通道

下面的例子通过单向通道计算了 1 到 10 的平方:

 

 

打印出了:

1

4

9

16

25

36

49

64

81

100

 

缓冲通道

上面通道的创建操作中,我们已经讲述过具有缓冲的通道的创建和使用

带有缓冲区的通道可以看作是一个队列,进行先入先出操作

 

获取缓冲通道的缓冲区容量和已缓冲元素数

 

 

通过上述两个方法,我们可以实现非阻塞的通道读写操作