Go语言八股之channel详解

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

前言

小郑最近在准备Go语言的面试题,通过github和b站等各种学习网站上学习go语言的八股文,并且整理出自己觉得面试可能会问到的知识点,希望通过做笔记的方式来巩固自己的知识点,并且也希望可以帮助到大家在面试的时候更加得心应手一些,那么从现在开始,和我一起加入八股学习之旅吧!

1.channel 是否线程安全?锁用在什么地方?

  1. Golang的Channel,发送一个数据到Channel 和 从Channel接收一个数据 都是 原子性的。
  2. 而且Go的设计思想就是:不要通过共享内存来通信,而是通过通信来共享内存,前者就是传统的加锁,后者就是Channel。
  3. 也就是说,设计Channel的主要目的就是在多任务间传递数据的,这当然是安全的

2.go channel 的底层实现原理 (数据结构)

Go面试题(五):图解 Golang Channel 的底层原理 - 掘金

chan-地鼠文档

3.向channel写数据

1. 如果等待接收队列 recvq 不为空

recvq 是 Channel 内部用于存储等待接收数据的 goroutine 队列。如果该队列不为空,意味着至少有一个 goroutine 正在等待接收数据。这时,发送操作会选择从 recvq 中取出一个等待接收的 goroutine,直接将数据写入给该 goroutine,然后将该 goroutine 唤醒。

解释:发送数据时如果有接收者准备好,数据就直接交给接收者,发送操作可以立刻完成,不需要通过缓冲区。

流程:从 recvq 中取出一个 goroutine,写入数据并唤醒它,发送过程完成。

2. 如果缓冲区中有空余位置

如果 Channel 是有缓冲的,并且缓冲区有空间,可以直接将数据写入缓冲区。

解释:在没有其他 goroutine 等待接收数据时,数据会直接存入 Channel 的缓冲区。这是一种最简单的情况,发送过程立即结束。

流程:将数据写入缓冲区,然后发送操作结束。

3. 如果缓冲区中没有空余位置

如果 Channel 已满且没有接收者(即 recvq 为空),数据将不会被立即写入,而是会被挂起。

解释:此时,发送操作无法立即完成,因为 Channel 没有空间,且没有 goroutine 等待接收数据。当前的发送 goroutine 会被挂起,直到有空间或者接收者存在。

流程:发送数据的 goroutine 会把待发送的数据存储在自己(发送者)的上下文中,并将自己加入到 sendq(等待发送的队列)中。然后,当前 goroutine 进入睡眠状态,等待其他 goroutine 处理数据(即接收数据),直到可以继续发送。


4.从channel读数据

1. 等待发送队列 sendq 不为空,且没有缓冲区(无缓冲 Channel)

场景:这是一个无缓冲 Channel,或者在缓冲 Channel 中数据已经满了。此时有 goroutine 正在等待发送数据。

操作:在此情况下,读取操作会从 sendq 中取出一个等待发送的 goroutine,并从中读取数据。这就像是在等待数据准备好,读操作会立刻取走数据并完成。然后,读取完数据后会唤醒这个 goroutine,告诉它数据已经被读取。

流程:从 sendq 取出一个 goroutine,读取数据,然后唤醒该 goroutine,读取过程完成。

2. 等待发送队列 sendq 不为空,且缓冲区已满

场景:这是一个缓冲 Channel,但缓冲区已满,无法继续直接从缓冲区读取数据。这时发送数据的 goroutine 需要等待接收数据的 goroutine 从缓冲区中取走数据。

操作:当发送队列中有待发送的数据时,首先从缓冲区的首部读取数据。如果缓冲区中的数据还没有被读出,那么就将发送的 goroutine 数据写入缓冲区的尾部。完成这些后,再唤醒等待的 goroutine,结束读取操作。

流程:首先从缓冲区中读取数据,然后将新数据写入缓冲区并唤醒 sendq 中的 goroutine,读取过程完成。

3. 缓冲区中有数据

场景:这是一个缓冲 Channel,并且缓冲区中有数据可供读取。这是最简单的一种情况,读取操作会直接从缓冲区取出数据。

操作:如果缓冲区中有数据,读取操作直接从缓冲区获取数据并完成,读取过程结束。

流程:直接从缓冲区中取出数据,读取过程完成。

4. 当前 goroutine 加入 recvq,进入睡眠状态

场景:如果在读取数据时没有满足上述条件(比如 sendq 为空,缓冲区没有数据可读),当前的读取 goroutine 会被挂起并进入睡眠状态,等待其他 goroutine 写入数据。

操作:如果没有数据可以读取,当前的读取 goroutine 会被加入到 recvq(接收队列)中,并进入阻塞状态,直到其他 goroutine 将数据写入缓冲区或发送队列,唤醒当前的读取 goroutine。

流程:当前的读取 goroutine 被加入到 recvq,然后挂起(睡眠),直到其他 goroutine 写入数据并唤醒它。

4.1讲讲 Go 的 chan 底层数据结构和主要使用场景

答:channel 的数据结构包含 qccount 当前队列中剩余元素个数,dataqsiz 环形队列长度,即可以存放的元素个数,buf 环形队列指针,elemsize 每个元素的大小,closed 标识关闭状态,elemtype 元素类型,sendx 队列下表,指示元素写入时存放到队列中的位置,recv 队列下表,指示元素从队列的该位置读出。recvq 等待读消息的 goroutine 队列,sendq 等待写消息的 goroutine 队列,lock 互斥锁,chan 不允许并发读写。

使用场景: 消息传递、消息过滤,信号广播,事件订阅与广播,请求、响应转发,任务分发,结果汇总,并发控制,限流,同步与异步

5.channel 在什么情况下会引起资源泄漏

Channel 可能会引发 goroutine 泄漏。

泄漏的原因是 goroutine 操作 channel 后,处于发送或接收阻塞状态,而 channel 处于满或空的状态,一直得不到改变。同时,垃圾回收器也不会回收此类资源,进而导致 gouroutine 会一直处于等待队列中,不见天日。

另外,程序运行过程中,对于一个 channel,如果没有任何 goroutine 引用了,gc 会对其进行回收操作,不会引起内存泄漏。

❤️❤️❤️小郑是普通学生水平,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

相关推荐
南囝coding44 分钟前
CSS终于能做瀑布流了!三行代码搞定,告别JavaScript布局
前端·后端·面试
pumpkin845141 小时前
Go 基础语法全景
开发语言·后端·golang
踏浪无痕1 小时前
Go 的协程是线程吗?别被"轻量级线程"骗了
后端·面试·go
一只叫煤球的猫2 小时前
为什么Java里面,Service 层不直接返回 Result 对象?
java·spring boot·面试
求梦8202 小时前
字节前端面试复盘
面试·职场和发展
C雨后彩虹3 小时前
书籍叠放问题
java·数据结构·算法·华为·面试
码农水水4 小时前
中国电网Java面试被问:流批一体架构的实现和状态管理
java·c语言·开发语言·面试·职场和发展·架构·kafka
程序员清风4 小时前
猿辅导二面:线上出现的OOM是如何排查的?
java·后端·面试
CCPC不拿奖不改名4 小时前
数据处理与分析:pandas基础+面试习题
开发语言·数据结构·python·面试·职场和发展·pandas
小徐不徐说4 小时前
避坑指南:Qt 中 Lambda 表达式崩溃原因与高效使用实践
数据库·c++·qt·面试