无限缓冲的channel(1)

简介: 无限缓冲的channel(1)

开篇介绍


我们都知道channel有两种类型:无缓冲和有缓冲的

当我们创建一个有缓冲的通道并指定了容量,那么在这个通道的生命周期内,我们将再也无法改变它的容量。

有时候,我们并不知道也无法预估写入通道的数量规模。如果此时通道的写入速度远远超过读取速度,那么必然会在某个时间点塞满通道导致写入阻塞。

比如之前我翻译的一篇文章使用 Go 每分钟处理百万请求中,作者就出现处理速度太慢,导致通道塞满,其他请求被阻塞,响应时间慢慢增加

此时有人就会提到,能不能提供一个无限缓冲(Unbounded or Unlimited)的通道。

这个问题早在 2017 年就有人提过 issues,最终 go 官方没有实现这个提案。

不过,这个 issues 下面总共产生了 67 个 comments,评论很精彩

1668505293347.jpg

比如有人提到:

cznic:Unlimited capacity channels ask for a machine with unlimited memory.

那么如何实现一个无限缓冲的通道呢?


针对这类需求,有很多版本的实现,我们来看其中的一个实现。鸟窝的 chanx 就是在这个基础上做修改的。

我们一步步还原它的实现,这其中还能知道作者的思考过程


代码实现


第一版,

1668505316681.jpg

MakeInfinite函数返回两个通道,第一个用于数据的写入,第二个用于数据的读取。

注意看这里的细节,在返回的时候就约束了通道的操作类型:一个只写,一个只读,这样避免了用户破坏通道的操作流程。 这里面的代码也简单只要写入通道in未被关闭那么就把从in通道中读取的值 appendinQueue切片中inQueue在这里就是实现无限缓冲的中间层。

然后有个 test。

1668505334687.jpg

1668505347917.jpg

当走到第二个case的时候,由于inQueue一开始是空的,那么必然会出现index out不仅是一开始,在运行中,如果读取比写入快,那么必然也会导致相同的情况。

1668505379504.jpg

1668505389935.jpg

inQueue没有值的时候我们把nil也写入到通道, 然后测试代码中我们从out channel读取值试图把值断言int失败了那么,当队列中没有数据时,我们不应该写入out通道

1668505401330.jpg

作者使用了一个技巧如果inQueue没有数据,那么尝试写入一个nil通道将永远阻塞。 通常永久阻塞是一个不好的行为但是这个是包含在select语句中的,所以问题不大。

1668505413325.jpg

还有问题。原因很简单,我们再发送完数据就马上关闭了in通道。随后break loop接下来关闭out通道,程序运行结束此时 inQueue还有值未被取出。

只要写比读快,那么就永远存在这个问题。我们需要保证在通道关闭的时候inQueue已为空。

1668505427074.jpg


总结


上面是如何实现一个无限缓冲的 channel

答:借助了一个临时存储数据的中间层。


上面的实现有没有哪些地方可以改进?

inQueue作为中间层,本质上是一个切片。如果 inQueue已经扩容到很大的值了,但是并没有对应的reset会导致inQueue指向还在底层数组靠后的位置,并不能复用数组前面的空间,造成浪费

chanx是咋么改进的

下一篇。


参考


https://github.com/golang/go/issues/20352

https://colobu.com/2021/05/11/unbounded-channel-in-go

https://medium.com/capital-one-tech/building-an-unbounded-channel-in-go-789e175cd2cd

相关文章
|
6月前
|
存储 编解码 移动开发
技术笔记:NIO流—理解Buffer、Channel概念和NIO的读写操作
技术笔记:NIO流—理解Buffer、Channel概念和NIO的读写操作
43 1
|
4月前
|
存储 消息中间件 缓存
|
5月前
|
存储 Go
GO通道:无缓冲通道与缓冲通道
GO通道:无缓冲通道与缓冲通道
43 0
|
7月前
|
存储 Go
|
7月前
|
编解码 网络协议
Netty基础篇:NIO中缓冲区设置太小
Netty基础篇:NIO中缓冲区设置太小
|
存储 消息中间件 NoSQL
计网 - 流和缓冲区:缓冲区的 flip 是怎么回事?
计网 - 流和缓冲区:缓冲区的 flip 是怎么回事?
100 0
|
存储 缓存
无限缓冲的channel(2)
无限缓冲的channel(2)
171 0
无限缓冲的channel(2)
golang channel 有缓冲 与 无缓冲 的重要区别
golang channel 有缓冲 与 无缓冲 的重要区别
IO流的字节流的缓冲和非缓冲方式的区别及性能对比
IO流的字节流的缓冲和非缓冲方式的区别及性能对比
267 0
|
机器学习/深度学习 索引
【Netty】NIO 缓冲区 ( Buffer ) ( 缓冲区读写类型 | 只读缓冲区 | 映射字节缓冲区 )(二)
【Netty】NIO 缓冲区 ( Buffer ) ( 缓冲区读写类型 | 只读缓冲区 | 映射字节缓冲区 )(二)
137 0
【Netty】NIO 缓冲区 ( Buffer ) ( 缓冲区读写类型 | 只读缓冲区 | 映射字节缓冲区 )(二)