深入理解Go语言中的Channel

发表时间: 2024-01-21 17:53

大家好,勾廊开发中channel使用的非常广泛,现在网上对channel的解析也非常多,这里分享一下个人对channel的理解。感觉channel类似于io流的概念,它分为流入和流出。

·在代码里面进行申请channel可以使用mac方法,channel分为有缓冲和无缓冲,这里也是声明无缓冲的channel。在实线上感觉就类似于图片里描述的这种,它分为流入和流出两个方向。如果只有流入没有流出,channel就直接发生阻塞。

·下面就是有缓冲的channel的图片,有缓冲的channel会有一个环形数组,保存相应容量的颤抖的元素。一旦超出容量之后会把阻塞的颤抖放到阻塞的环形对列里面,相应的也会有流入和流出。在不超过环形缓冲容量的情况下不会发生阻塞。

·像channel的数据结构可以从代码中观察到,可以从channel的数据结构印证一下图片的说法。channel数据结构里面有qquant标记元素的容量,有buffer环形数组存放相应的元素。在元素超出容量之后会有应接收线路阻塞的形成对列和音发送,发送线路阻塞的形成对列,同时还有一个锁来解决并发的问题。

关于阻塞发送和接收china超出容量的时候都会陷入阻塞状态,看一下发生阻塞和阻塞是如何解除的。假设在读取一个空的channel没有写入的情况下,channel会陷入阻塞状态。通过看一下读取channel的原码发现主要是通过gopak将携程陷入阻塞状态,这个时候g也携程会与当前的线程进行解码,等待下一次调度。

具体的代码是在runtimechannel里面会有gopark的调用,这个时候携程会陷入阻塞状态,在这里就类似于一直阻塞,下面的代码就不会执行。

什么时候会再次被唤醒?如果选程序的时候也会发现如果有写入方向channel里面写入数据,原来的channel原来的行程就会再次被唤醒。所有的代码追踪可以看一下,在sing the channel的时候会有go ready的调用,go ready是将携程从阻塞态变成可调度态。

可调度态情况的下会走gmp调度处理,当真正的被调度成功的时候就会把当前携程给唤醒,唤醒之后会继续下面的执行下面的代码,下面代码直接会把当前元素给释放掉。因为在相应的写操作的时候会把出版相应的元素给直接处理了,这里就不用重复再处理了,直接释放掉走下面的操作。

如果一个携程已经陷入阻塞状态为什么还能监听到数据?因为携程在select状态下不会真正的陷入阻塞状态,它会有一个类似于自旋的状态,实际上还是能监听到写入和读出的数据。这是因为在原码里面史莱克的状态下会走不同于写和发送数据的方法,会有一个非阻塞的标识,在这个标识下不会直接调用gopak进行阻色态,所以能正常的接收到数据。

感谢大家的收看,这个就是分享一下自己对参照的理解。