面试官:谈谈 Go Channel?我讲了个故事,把他讲懵了

25 阅读4分钟

又一个程序员被 Channel 面试题难住了

那天,一位朋友去面试。

面试官抬头,看了他一眼,淡淡问道:

“谈谈你对 Go Channel 的理解?带缓冲和不带缓冲有什么区别?”

朋友内心大喊:完了,这题我明明天天写,但就是讲不清!

嘴上却只能磕磕绊绊地挤出几句:

“呃……不带缓冲会阻塞……带缓冲就不太阻塞……然后……close 以后还能读……反正……挺神奇的。”

面试官的眉毛缓缓扬起,仿佛在说:

“你是不是只会用,却不知道为什么?”

其实不怪他。 Go 的 Channel 用起来这么丝滑,但底层原理远比很多人想象得深。

下面我就用一个故事,把这个问题彻底讲透。 看完你会有一种感觉:

“原来 channel 是这么回事!早该有人这样讲了。”

Go 语言物流公司的奇妙一天

欢迎来到“Go 时空物流公司”。

在这里,程序中的每一次 Channel 通信,都对应一段奇妙的物流流程。

主角有三位:

  • 小发:负责发送包裹(发送方 Goroutine)
  • 小收:负责接收包裹(接收方 Goroutine)
  • Channel 传送带:神奇的时空中转站

你以为它只是一个队列? 不,它更重要的作用是同步人与人。

无缓冲 Channel ——“手递手”的精准交付

无缓冲 Channel 就像一个没有储物柜的传送带。

规则很简单:

发送和接收双方必须同时出现,否则谁都动不了。

小发抱着包裹来到传送带前,发现没人接货,只能坐在地上等待(阻塞)。

小收稍后赶来,看到小发在睡觉,就拍拍他:“兄弟醒醒,我来了。”

两人“手递手”完成交接,各自离开。

这就是无缓冲 channel 的本质——动作同步。

带缓冲 Channel ——自动储物柜的魔法仓库

带缓冲 channel 的传送带旁边多了一个储物柜。

容量为 dataqsiz = N。

小发发包裹时:

  • 储物柜没满,就把包裹一扔,走人。
  • 满了,只能坐下等(阻塞)。

小收取包裹时:

  • 储物柜不空,他随时能来取。
  • 空了,就得睡觉等小发来送。

储物柜的存在让发送与接收从“必须同步”,变成“可以异步”。

close(channel) ——管理员拉下电闸

某天管理员冲进来:

“传送带要关闭了!”

他拉下开关,channel 被关闭。

从此:

  1. 小发再试图发送包裹,将立即触发事故(panic)。
  2. 小收可以继续把储物柜里的包裹取完。
  3. 当最后一个包裹取完后,再取就会得到零值和 ok=false,而不会阻塞。

关闭 channel 的含义是:入口关闭,但库存还可以取。

事故现场 ——panic 场景

几种典型事故:

  1. 向关闭的 channel 发送值 → panic
  2. 关闭一个已关闭的 channel → panic
  3. 关闭 nil channel → panic

但从关闭的 channel 取值不会 panic。

hchan 的底层结构

Go 的 runtime 中,channel 用 hchan 表示:

type hchan struct {
    qcount   uint           // 当前储物柜中的包裹数
    dataqsiz uint           // 储物柜容量
    buf      unsafe.Pointer // 储物柜本体
    sendx    uint           // 下一个包裹要放的位置
    recvx    uint           // 下一个包裹要取的位置
    recvq    waitq          // 等待接收的队列
    sendq    waitq          // 等待发送的队列
    closed   uint32         // 是否已关闭
}

对应关系如下:

  • dataqsiz:储物柜容量
  • qcount:当前包裹数
  • buf:储物柜数组
  • sendx:小发放包裹的位置
  • recvx:小收取包裹的位置
  • sendq:等待发货的小发队列
  • recvq:等待收货的小收队列
  • closed:电闸状态

看到这里,是不是觉得:

“原来我一直在和一个物流系统打交道。”

Channel 的本质

用一句话结尾:Channel 的本质不是传递数据,而是协调 goroutine 之间同步的通信工具。

数据只是顺带传一下,真正核心是同步。

最后问你一个问题

你在项目中遇到过哪些和 channel 相关的坑?欢迎留言分享。

如果这篇文章让你有所顿悟,欢迎点赞、转发、收藏。我会继续用故事把技术讲得更有温度。


image.png