专栏首页吴亲强的深夜食堂无限缓冲的channel(1)
原创

无限缓冲的channel(1)

介绍

事情的起因是前几周看到鸟窝写了一篇关于实现无限缓冲 channel 的文章,当时忙着和小姐姐聊天没看,今天想起来了。

不过这篇文章不会涉及到鸟窝自己实现的 chanx,我们会在下一篇提到。

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

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

有时候,我们并不知道也无法预估写入通道的数量规模。如果此时通道的写入速度远远超过读取速度,那么必然会在某个时间点塞满通道,导致写入阻塞。 比如之前我翻译的一篇文章 使用 Go 每分钟处理百万请求 中,作者就出现处理速度太慢,导致通道塞满,其他请求被阻塞,响应时间慢慢增加。

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

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

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

比如有人提到:

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

rsc:The limited capacity of channels is an important source of backpressure in a set of communicating goroutines. It is typically a mistake to use an unbounded channel, because you lose that backpressure. If one goroutine falls sufficiently behind, you usually want to take some action in response, not just queue its messages forever. The appropriate response varies by situation: maybe you want to drop messages, maybe you want to keep summary messages, maybe you want to take different responses as the goroutine falls further and further behind. Making it trivial to reach for unbounded channels keeps developers from thinking about this, which I believe is a strong disadvantage.

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

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

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

代码

第一版,

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

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

然后有个 test。

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

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

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

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

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

总结

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

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

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

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

chanx 是咋么改进的?

下一篇

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 无限缓冲的channel(2)

    上篇文章我们提到,当我们创建一个有缓冲的通道并指定了容量,那么在这个通道的生命周期内,我们将再也无法改变它的容量。 由此引发了关于无限缓存的 channel 话...

    吴亲库里
  • golang 无缓冲channel

    landv
  • 【Go 语言社区】golang channel 有缓冲 与 无缓冲 的重要区别

    golang channel 有缓冲 与 无缓冲 是有重要区别的 我之前天真的认为 有缓冲与无缓冲的区别 只是 无缓冲的 是 默认 缓冲 为1 的缓冲式 其实是...

    李海彬
  • C的全缓冲、行缓冲和无缓冲

    基于流的操作最终会调用read或者write函数进行I/O操作。为了使程序的运行效率最高,流对象通常会提供缓冲区,以减少调用系统I/O库函数的次数。

    Dabelv
  • CC++的全缓冲、行缓冲和无缓冲

    C/C++中,基于I/O流的操作最终会调用系统接口read()和write()完成I/O操作。为了使程序的运行效率最高,流对象通常会提供缓冲区,以减少调用系统I...

    Dabelv
  • Java.NIO编程一览笔录

    Java标准IO 与 Java NIO 的简单差异示意: Java标准IO Java NIO API调用 简单 复杂 底层实现 面向流(str...

    斯武丶风晴
  • 抛砖引玉NIO

    在软件系统中,由于I/O的速度远比内存速度慢,所以I/O很容易成为系统的瓶颈。New I/O的简称,与旧式基于流的I/O相对。拥有如下特性:

    三哥
  • Coroutine(协程)(三)

    一个 Channel 是一个和 BlockingQueue 非常相似的概念。其中一个不同是它代替了阻塞的 put 操作并提供了挂起的 send,还替代了阻塞的 ...

    提莫队长
  • Java NIO之Java中的IO分类

    前面两篇文章(Java NIO之理解I/O模型(一)、Java NIO之理解I/O模型(二))介绍了,IO的机制,以及几种IO模型的内容,还有涉及到的设计模式。...

    纪莫
  • Netty4学习笔记 --- Netty入门

    互联网行业: 在分布式系统中,各个节点之间需要远程服务调用,高性能的 RPC 框架必不可少,Netty 作为异步高性能的通信框架,往往作为基础通信组件被这些 ...

    挽风
  • 走进Golang之Channel的使用

    相信写过 Go 的同学都知道这句名言,可以说 channel 就是后边这句话的具体实现。我们来看一下到底 channel 是什么?

    大愚
  • Netty系列| Netty创始人告诉你为什么选择NIO

    NIO模型 同步非阻塞 NIO有同步阻塞和同步非阻塞两种模式,一般讲的是同步非阻塞,服务器实现模式为一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器...

    狼王编程
  • 了解NIO和BIO

    1.linux系统中一切皆文件当有文件 当有一个请求过来的時候就通过3次握手就会和内核创建连接关系,此时Tomcat中的启动的的端口监控就会检测到内核中的文件...

    居士
  • 你知道IO与NIO有什么区别吗?

    阻塞与非阻塞是描述进程在访问某个资源时,数据是否准备就绪的的一种处理方式。当数据没有准备就绪时:

    Java深度编程
  • Netty中的这些知识点,你需要知道!

    Channel是一个接口,而且是一个很大的接口,我们称之为“大而全”,囊括了server端及client端接口所需要的接口。

    WindWant
  • Netty之JavaNIO编程模型介绍01

      Java NIO 全称 java non-blocking IO,是指 JDK 提供的新 API。从 JDK1.4 开始,Java 提供了一系列改进的输入/...

    用户4919348
  • Java IO与NIO

    七 Java NIO AsynchronousFileChannel异步文件通

    后端码匠
  • 万字长文:助你攻破 JAVA NIO 技术壁垒

    现在使用NIO的场景越来越多,很多网上的技术框架或多或少的使用NIO技术,譬如Tomcat,Jetty。学习和掌握NIO技术已经不是一个JAVA攻城狮的加分技能...

    猿天地
  • 深度解密Go语言之channel

    大家好啊!“深度解密 Go 语言”系列好久未见,我们今天讲 channel,预祝阅读愉快!在开始正文之前,我们先说些题外话。

    梦醒人间

扫码关注云+社区

领取腾讯云代金券