Go语言带缓冲的通道实现


Posted in Golang onApril 26, 2021

Go语言中有缓冲的通道(buffered channel)是一种在被接收前能存储一个或者多个值的通道。这种类型的通道并不强制要求 goroutine 之间必须同时完成发送和接收。通道会阻塞发送和接收动作的条件也会不同。只有在通道中没有要接收的值时,接收动作才会阻塞。只有在通道没有可用缓冲区容纳被发送的值时,发送动作才会阻塞。

这导致有缓冲的通道和无缓冲的通道之间的一个很大的不同:无缓冲的通道保证进行发送和接收的 goroutine 会在同一时间进行数据交换;有缓冲的通道没有这种保证。

在无缓冲通道的基础上,为通道增加一个有限大小的存储空间形成带缓冲通道。带缓冲通道在发送时无需等待接收方接收即可完成发送过程,并且不会发生阻塞,只有当存储空间满时才会发生阻塞。同理,如果缓冲通道中有数据,接收时将不会发生阻塞,直到通道中没有数据可读时,通道将会再度阻塞。

无缓冲通道保证收发过程同步。无缓冲收发过程类似于快递员给你电话让你下楼取快递,整个递交快递的过程是同步发生的,你和快递员不见不散。但这样做快递员就必须等待所有人下楼完成操作后才能完成所有投递工作。如果快递员将快递放入快递柜中,并通知用户来取,快递员和用户就成了异步收发过程,效率可以有明显的提升。带缓冲的通道就是这样的一个“快递柜”。

创建带缓冲通道

如何创建带缓冲的通道呢?参见如下代码:

通道实例 := make(chan 通道类型, 缓冲大小)

  • 通道类型:和无缓冲通道用法一致,影响通道发送和接收的数据类型。
  • 缓冲大小:决定通道最多可以保存的元素数量。
  • 通道实例:被创建出的通道实例。

下面通过一个例子中来理解带缓冲通道的用法,参见下面的代码:

package main
import "fmt"
func main() {
    // 创建一个3个元素缓冲大小的整型通道
    ch := make(chan int, 3)
    // 查看当前通道的大小
    fmt.Println(len(ch))
    // 发送3个整型元素到通道
    ch <- 1
    ch <- 2
    ch <- 3
    // 查看当前通道的大小
    fmt.Println(len(ch))
}

代码输出如下:
0
3

代码说明如下:

  • 第 8 行,创建一个带有 3 个元素缓冲大小的整型类型的通道。
  • 第 11 行,查看当前通道的大小。带缓冲的通道在创建完成时,内部的元素是空的,因此使用 len() 获取到的返回值为 0。
  • 第 14~16 行,发送 3 个整型元素到通道。因为使用了缓冲通道。即便没有 goroutine 接收,发送者也不会发生阻塞。
  • 第 19 行,由于填充了 3 个通道,此时的通道长度变为 3。

阻塞条件

带缓冲通道在很多特性上和无缓冲通道是类似的。无缓冲通道可以看作是长度永远为 0 的带缓冲通道。因此根据这个特性,带缓冲通道在下面列举的情况下依然会发生阻塞:

  • 带缓冲通道被填满时,尝试再次发送数据时发生阻塞。
  • 带缓冲通道为空时,尝试接收数据时发生阻塞。

为什么Go语言对通道要限制长度而不提供无限长度的通道?

我们知道通道(channel)是在两个 goroutine 间通信的桥梁。使用 goroutine 的代码必然有一方提供数据,一方消费数据。当提供数据一方的数据供给速度大于消费方的数据处理速度时,如果通道不限制长度,那么内存将不断膨胀直到应用崩溃。因此,限制通道的长度有利于约束数据提供方的供给速度,供给数据量必须在消费方处理量+通道长度的范围内,才能正常地处理数据。

到此这篇关于Go语言带缓冲的通道实现的文章就介绍到这了,更多相关Go语言带缓冲通道内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
win10下go mod配置方式
Apr 25 Golang
基于Go Int转string几种方式性能测试
Apr 28 Golang
golang 在windows中设置环境变量的操作
Apr 29 Golang
golang日志包logger的用法详解
May 05 Golang
go类型转换及与C的类型转换方式
May 05 Golang
Go语言空白表示符_的实例用法
Jul 04 Golang
基于Go语言构建RESTful API服务
Jul 25 Golang
Go 语言中 20 个占位符的整理
Oct 16 Golang
Go并发4种方法简明讲解
Apr 06 Golang
golang操作redis的客户端包有多个比如redigo、go-redis
Apr 14 Golang
Golang 结构体数据集合
Apr 22 Golang
Golang 实现WebSockets
Apr 24 Golang
go语言求任意类型切片的长度操作
Apr 26 #Golang
golang如何去除多余空白字符(含制表符)
Apr 25 #Golang
用golang如何替换某个文件中的字符串
Apr 25 #Golang
Golang 正则匹配效率详解
golang正则之命名分组方式
Apr 25 #Golang
go语言-在mac下brew升级golang
Apr 25 #Golang
go原生库的中bytes.Buffer用法
Apr 25 #Golang
You might like
php生成不重复随机数、数组的4种方法分享
2015/03/30 PHP
前端必学之PHP语法基础
2016/01/01 PHP
YII CLinkPager分页类扩展增加显示共多少页
2016/01/29 PHP
PHP模板引擎Smarty中的保留变量用法分析
2016/04/11 PHP
javascript jQuery插件练习
2008/12/24 Javascript
一个封装js代码-----展开收起效果示例
2013/07/03 Javascript
JS实现可拖曳、可关闭的弹窗效果
2015/09/26 Javascript
Jquery组件easyUi实现手风琴(折叠面板)示例
2016/08/23 Javascript
Bootstrap的基本应用要点浅析
2016/12/19 Javascript
AngularJS实现注册表单验证功能
2017/10/16 Javascript
浅谈Koa2框架利用CORS完成跨域ajax请求
2018/03/06 Javascript
vue中手机号,邮箱正则验证以及60s发送验证码的实例
2018/03/16 Javascript
原生JS封装_new函数实现new关键字的功能
2018/08/12 Javascript
layui自己添加图片按钮并点击跳转页面的例子
2019/09/14 Javascript
vue实现图片上传功能
2020/05/28 Javascript
Python字符编码判断方法分析
2016/07/01 Python
Python执行时间的计算方法小结
2017/03/17 Python
Python OpenCV获取视频的方法
2018/02/28 Python
python调用系统ffmpeg实现视频截图、http发送
2018/03/06 Python
详解PyTorch批训练及优化器比较
2018/04/28 Python
Python 使用类写装饰器的小技巧
2018/09/30 Python
Python关于excel和shp的使用在matplotlib
2019/01/03 Python
Python分支语句与循环语句应用实例分析
2019/05/07 Python
将Python字符串生成PDF的实例代码详解
2019/05/17 Python
python使用 request 发送表单数据操作示例
2019/09/25 Python
巴西24小时在线药房:Drogasil
2020/06/20 全球购物
linux面试相关问题
2012/08/11 面试题
九年级家长会邀请函
2014/01/15 职场文书
党员公开承诺事项
2014/03/25 职场文书
园艺师求职信
2014/04/27 职场文书
班主任个人工作反思
2014/04/28 职场文书
保洁公司服务承诺书
2014/05/28 职场文书
2015年党风廉政承诺书
2015/01/22 职场文书
教师个人年度总结
2015/02/11 职场文书
html+css合并表格边框的示例代码
2021/03/31 HTML / CSS
Nginx配置使用详解
2022/07/07 Servers