【Golang】Channel的ring buffer实现

文章目录

  • 前言
  • 一、介绍
  • 三、环形缓冲区的实现原理
  • 三、使用方式
  • 四、总结


前言

在并发编程中,channel 是 Golang 提供的一种用于 goroutine 之间通信的机制。channel 的底层实现是一个环形缓冲区,这种设计使得 channel 在处理大量数据传输时能够保持高效。本文将详细介绍 Golang 中 channel 的环形缓冲区实现原理,帮助读者更好地理解 channel 的工作机制。


一、介绍

1. 环形缓冲区的基本概念

环形缓冲区(ring buffer),也称为循环缓冲区,是一种固定大小的缓冲区,逻辑上将其首尾相连形成一个环。当缓冲区满时,新的数据会覆盖最旧的数据。环形缓冲区具有高效的入队和出队操作,适用于需要频繁进行数据传输的场景。

2. Golang 中 channel 的环形缓冲区实现

在 Golang 中,channel 的底层实现是一个环形缓冲区。channel 的结构体定义在 runtime/chan.go 文件中,主要包含以下几个字段:

type hchan struct {qcount   uint           // 队列中的数据个数dataqsiz uint           // 环形缓冲区的大小buf      unsafe.Pointer // 环形缓冲区的指针elemsize uint16         // 元素的大小closed   uint32         // channel 是否关闭sendx    uint           // 发送操作的索引recvx    uint           // 接收操作的索引recvq    waitq          // 等待接收的 goroutine 队列sendq    waitq          // 等待发送的 goroutine 队列lock     mutex          // 互斥锁
}

三、环形缓冲区的实现原理

1. 发送操作
当一个 goroutine 向 channel 发送数据时,channel 会将数据存储在环形缓冲区中。如果缓冲区已满,发送操作会阻塞,直到有空间可用。

发送操作的步骤如下:

1.获取互斥锁,确保操作的原子性。
2.检查缓冲区是否已满。如果已满,将当前 goroutine 添加到发送队列中并阻塞。
3.将数据写入环形缓冲区,并更新发送索引 sendx。
4.释放互斥锁。
示例代码:

func send(c *hchan, elem unsafe.Pointer) {lock(&c.lock)if c.qcount == c.dataqsiz {// 缓冲区已满,阻塞发送goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 2)return}// 将数据写入缓冲区typedmemmove(c.elemtype, chanbuf(c, c.sendx), elem)c.sendx++if c.sendx == c.dataqsiz {c.sendx = 0}c.qcount++unlock(&c.lock)
}

2. 接收操作
当一个 goroutine 从 channel 接收数据时,channel 会从环形缓冲区中读取数据。如果缓冲区为空,接收操作会阻塞,直到有数据可用。

接收操作的步骤如下:
1.获取互斥锁,确保操作的原子性。
2.检查缓冲区是否为空。如果为空,将当前 goroutine 添加到接收队列中并阻塞。
3.从环形缓冲区读取数据,并更新接收索引 recvx。
4.释放互斥锁。
示例代码:

func recv(c *hchan, elem unsafe.Pointer) {lock(&c.lock)if c.qcount == 0 {// 缓冲区为空,阻塞接收goparkunlock(&c.lock, "chan recv", traceEvGoBlockRecv, 2)return}// 从缓冲区读取数据typedmemmove(c.elemtype, elem, chanbuf(c, c.recvx))c.recvx++if c.recvx == c.dataqsiz {c.recvx = 0}c.qcount--unlock(&c.lock)
}

3. 环形缓冲区的优点
环形缓冲区具有以下优点:

  • 高效的入队和出队操作:环形缓冲区的入队和出队操作时间复杂度为 O(1),非常高效。
  • 固定大小:环形缓冲区的大小在创建时确定,避免了动态内存分配的开销。
  • 避免内存碎片:环形缓冲区使用连续的内存块,避免了内存碎片问题。

三、使用方式

1. 创建和使用无缓冲 channel
无缓冲 channel 的发送和接收操作是同步的,发送方和接收方必须同时准备好。
示例:

package mainimport ("fmt"
)func main() {ch := make(chan int)go func() {ch <- 42  // 发送数据}()value := <-ch  // 接收数据fmt.Println(value)  // 输出:42
}

2. 创建和使用有缓冲 channel
有缓冲 channel 允许在缓冲区未满时进行非阻塞发送,在缓冲区非空时进行非阻塞接收。

示例:

package mainimport ("fmt"
)func main() {ch := make(chan int, 2)  // 创建一个缓冲区大小为 2 的 channelch <- 1  // 非阻塞发送ch <- 2  // 非阻塞发送fmt.Println(<-ch)  // 输出:1fmt.Println(<-ch)  // 输出:2
}

四、总结

Golang 中的 channel 通过环形缓冲区实现了高效的并发通信机制。环形缓冲区具有高效的入队和出队操作,适用于需要频繁进行数据传输的场景。通过理解 channel 的环形缓冲区实现原理,开发者可以更好地利用 channel 进行并发编程,编写出高性能、易维护的并发程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/60201.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

隧道论文阅读2-采用无人融合扫描数据的基于深度学习的垂直型隧道三维数字损伤图

目前存在的问题&#xff1a; 需要开发新的无人测量系统测量垂直隧道图像数据量巨大&#xff0c;基于深度学习完成损伤评估跟踪获取图像位置的困难&#xff0c;对大型基础设施感兴趣区域(roi)的2d和3d地图建立进行了研究&#xff0c;对整个目标结构的损伤定位仍然具有挑战性。为…

深入提升Python编程能力的全方位指南

Python作为一种强大且灵活的编程语言&#xff0c;广泛应用于数据科学、机器学习、网络开发、自动化等领域。提升Python编程技术需要结合多方面的知识和技能。本文将详细介绍通过掌握核心技术、项目实践和代码示例来系统提升Python编程技能的方法。 一、掌握基础和高级Python特…

HCIP-HarmonyOS Application Developer V1.0 笔记(五)

弹窗功能 prompt模块来调用系统弹窗API进行弹窗制作。 当前支持3种弹窗API&#xff0c;分别为&#xff1a; 文本弹窗&#xff0c;prompt.showToast&#xff1b;对话框&#xff0c;prompt.showDialog&#xff1b;操作菜单&#xff0c;prompt.showActionMenu。 要使用弹窗功能&…

《深入浅出Apache Spark》系列③:Spark SQL解析层优化策略与案例解析

导读&#xff1a;本系列是Spark系列分享的第三期。第一期分享了Spark Core的一些基本原理和一些基本概念&#xff0c;包括一些核心组件。Spark的所有组件都围绕Spark Core来运转&#xff0c;其中最活跃的一个上层组件是Spark SQL。第二期分享则专门介绍了Spark SQL的基本架构和…

Linux应用——线程池

1. 线程池要求 我们创建线程池的目的本质上是用空间换取时间&#xff0c;而我们选择于 C 的类内包装原生线程库的形式来创建&#xff0c;其具体实行逻辑如图 可以看到&#xff0c;整个线程池其实就是一个大型的 CP 模型&#xff0c;接下来我们来完成它 2. 整体模板 #pragma …

算法每日双题精讲——滑动窗口(长度最小的子数组,无重复字符的最长子串)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…

PHP字符串变量

php字符串变量&#xff0c;也可以理解为一个存放文本的一样东西。 <?php$text"Hello world!"; //输出Hello world&#xff01; echo $text;?> 当赋一个文本值给变量时&#xff0c;请记得给文本值加上单引号或者双引号。 1、下面再来看看字符串的应用场景 …

HiveSQL 中判断字段是否包含某个值的方法

HiveSQL 中判断字段是否包含某个值的方法 在 HiveSQL 中&#xff0c;有时我们需要判断一个字段是否包含某个特定的值。下面将介绍几种常用的方法来实现这个功能。 一、创建示例表并插入数据 首先&#xff0c;我们创建一个名为employee的表&#xff0c;并插入一些示例数据&am…

vue2 - el-table表格设置动态修改表头

效果 代码 <template><el-card><!-- 搜索栏 --><Search :query

MySQL 8.0的Public Key Retrival问题解决

一、导致“Public Key Retrieval is not allowed”原因 该错误是在 JDBC 与 MySQL 建立 Connection 对象时出现的&#xff1b;需要明确的是出现该问题的时候&#xff0c;MySQL 配置的密码认证插件为如下两种&#xff1a; sha256_passwordcaching_sha2_password 使用“mysql_…

Java 集合遍历中删除元素的正确方法与陷阱

在 Java 开发中&#xff0c;经常会遇到遍历集合并删除特定元素的需求。乍一看&#xff0c;这似乎是一个简单的操作&#xff0c;但如果不注意方式&#xff0c;很容易踩坑。这篇文章将带你理解如何在 Java 中安全地删除集合元素&#xff0c;并避免 ConcurrentModificationExcepti…

sed超实用的文本处理工具

sed命令参数表 sed参数说明a在指定行的后面增加新航c替换指定行d删除行-e多次编辑&#xff0c;多次编辑后这样写回文件。sed -i -e /^[[:space:]]*#/d -e /^$/d nginx.confp打印行-r激活拓展正则-n取消默认输出-i静默编辑&#xff0c;屏幕上不显示编辑后的内容&#xff0c;放在…

GPU 环境搭建指南:如何在裸机、Docker、K8s 等环境中使用 GPU

本文主要分享在不同环境&#xff0c;例如裸机、Docker 和 Kubernetes 等环境中如何使用 GPU。 跳转阅读原文&#xff1a;GPU 环境搭建指南&#xff1a;如何在裸机、Docker、K8s 等环境中使用 GPU 1. 概述 仅以比较常见的 NVIDIA GPU 举例&#xff0c;系统为 Linux&#xff0c;…

MySQL-表数据操作

目录 一、INSERT-增加表中数据 二、DELETE-删除表中数据 三、UPDATE-修改表中数据 四、SELECT-查询表中数据 1、select基础查询 1.1 结果去重查询-DISTINCT 1.2 使用别名查询-AS 1.3 计算列 2、选择查询 2.1 比较搜索条件 2.2 范围搜索条件-BETWEEN AND 2.3 列表搜…

Vue中父组件通过v-model向子组件传对象参数

描述&#xff1a; Vue中父组件通过v-model向子组件传递一个对象&#xff0c;在子组件实现一个能够对object key-value进行编辑的组件封装。 父组件文件 <form-child v-model"configMap"></form-child>import formChild from /components/formchild.vue i…

mysql数据同步到sql server

准备工作 下载安装sql server express 2019 现在安装SSMS(连接数据库GUI) 安装ssms for mysql 需要注意的是在上面的步骤中首先需要根据指导安装mysql ODBC 设置express sa用户密码登录 --change password for login user "sa"Security > Logins > sa (rig…

如何解决企业业务流程分散的痛点

企业面临的一个普遍问题是业务流程的分散。业务流程分散不仅使得工作效率大幅下降&#xff0c;还增加了出错的风险&#xff0c;影响了企业的整体运营效率。因此&#xff0c;解决这一问题成为了许多企业亟需面对的挑战。 业务流程分散的原因 业务流程分散的根本原因&#xff0…

融入模糊规则的宽度神经网络结构

融入模糊规则的宽度神经网络结构 论文概述创新点及贡献 算法流程讲解模糊规则生成映射节点生成输出预测结果 核心代码复现main.py文件FBLS.py文件 使用方法测试结果示例&#xff1a;使用公开数据集进行本地训练准备数据数据输入模型进行训练实验结果 环境配置资源获取 本文所涉…

SQL常见语法

select * from student; select&#xff1a;选取 from&#xff1a;来源 *&#xff1a;所有栏位 select 姓名&#xff0c;班级&#xff0c;成绩 from students; 选取特定栏位 select 姓名&#xff0c;班级&#xff0c;成绩 from students limit 5;--限制显示拦数 select 姓…

Kafka Eagle 安装教程

目录 前言 一、安装前的准备 1. 系统要求 2. 安装 JDK 3. 安装 Kafka 和 Zookeeper 4. MySQL 环境准备 二、下载并安装 Kafka Eagle 三、配置 Kafka Eagle 1. 编辑配置文件 2. 配置 Kafka 和 Zookeeper 信息 四、启动 Kafka Eagle 五、访问 Kafka Eagle 六、测试功…