什么是 channel
在 Go 语言中,channel 可以称其为通道,也可以叫管道。channel 主要常见于与 goroutine+select 搭配使用,再结合语录的描述。可以知道 channel 就是用于 goroutine 的数据通信:
func main() {
ch := make(chan string)
go func() {
ch <- "煎鱼"
}()
msg := <-ch
fmt.Println(msg)
}
channel 基本特性
在 Go 语言中,channel 的关键字为 chan,数据流向的表现方式为 <-,代码解释方向是从左到右,据此就能明白通道的数据流转方向了。
channel 共有两种模式,分别是:双向和单向;三种表现方式,分别是:声明双向通道:chan T、声明只允许发送的通道:chan <- T、声明只允许接收的通道:<- chan T。
channel 中还分为 “无缓冲 channel” 和 “缓冲 channel”。
// 无缓冲
ch1 := make(chan int)
// 缓冲区为 3
ch2 := make(chan int, 3)
channel 本质
channel 听起来实现了一个非常酷的东西,也是日常工作中常常会被面试官问到的问题。
但其实 channel 并没有那么的 “神秘”,就是一个环形队列的配合。接下来我们一步步的剖开 channel,看看里面到底是什么,怎么实现的跨 goroutine 通信,数据结构又是什么,两者又如何实现数据传输的?
基本原理
本质上 channel 在设计上就是环形队列。其包含发送方队列、接收方队列,加上互斥锁 mutex 等结构。
channel 是一个有锁的环形队列
channel 实现原理
在了解了 channel 的基本原理后,我们进入到与应用工程中更紧密相关的部分,那就是 channel 的四大块操作,分别是: “创建、发送、接收、关闭”。 创建 channel 的逻辑主要分为三大块:
- 当前 channel 不存在缓冲区,也就是元素大小为 0 的情况下,就会调用
mallocgc方法分配一段连续的内存空间。 - 当前 channel 存储的类型存在指针引用,就会连同
hchan和底层数组同时分配一段连续的内存空间。 - 通用情况,默认分配相匹配的连续内存空间。