channel
golang-channel语雀笔记整理
注:以下内容是看小徐的公众号及B站学习源码做的笔记,个人理解,仅供参考
golang channel的设计动机?
channel是一种不同协程之间实现异步通信的数据结构。
golang中有一种很经典的说法是要基于通信实现共享内存,而不要基于共享内存实现通信。在操作系统内核视角下,线程是最小调度单元,不同线程共享内存空间这样实现的通信就很方便,但并不是共享的细节越多越好,好的架构应该是只共享对方需要关心的细节。
chanel通过语法级别上的消息队列实现共享,通过很简洁的api将需要关心的细节托付给channel,而不需要暴露所有细节。
chanel的数据结构/设计思考
所以综上可以推断channel的数据结构:
- channel需要面向并发实现异步通信,所以肯定有一把锁;
- chanel需要缓存数据的能力(比如定义的时候可以定义cap大小),所以一定有buf(通过双指针和一个数组实现的环形数组。双指针一个标记读从哪里开始,一个标记写从哪里开始。数组保证内存连续所以快,相比链表,省去了存放前后指针的空间,环形保证内存复用);
- channel需要有阻塞的功能,比如某个读协程由于channel没数据读,所以阻塞挂起了,后续channel有内容可读了如何找到这个协程并且唤醒?那么需要一种数据结构承载并且维护和管理协程,所以有阻塞的协程队列
channel阻塞问题:
往无缓冲channel中 读,但是没有数据并且不写,阻塞
往有缓冲channel中读, 但是缓冲为空,阻塞
往无缓冲中写,但是没有协程读,阻塞
往有缓冲中写,缓冲满了还没读,阻塞
有数据但是没读,close掉还是会阻塞
读的两种协议:读的时候如果 val <- chan,此时的读到0,是因为无数据可读还是因为关闭了?
所以 val , ok <- chan, 如果ok为ture,此时的0是数据0,ok为false,0是无数据可读的0
chanel的close