Go的数据结构与实现【Ring Buffer】

介绍

在本文中,我们将用Go实现环形缓冲区(Ring Buffer)

Ring Buffer

环形缓冲区(或循环缓冲区)是一种有界循环数据结构,用于在两个或多个线程之间缓冲数据。当我们继续写入环形缓冲区时,它会在到达末尾时回绕。

原理

环形缓冲区是使用在边界处环绕的固定大小数组实现的。
除了数组之外,它还保留了三个关键变量位置:

  • 缓冲区中用于插入元素的下一个可用插槽,
  • 缓冲区中的下一个未读元素,
  • 数组的结尾,即缓冲区环绕到数组开头的点
    -

环形缓冲区如何处理这些要求的机制因实现而异。我们需要知道的第一件事是容量,缓冲区的固定最大大小。接下来,我们将使用两个单调递增的序列:

  • 写入序列:从-1开始,在我们插入元素时递增1
  • 读取序列:从0开始,随着我们消耗一个元素递增1我们可以使用取模操作将序列映射到数组中的索引:

arrayIndex = sequence % capacity

取模操作在边界周围将序列连接起来,序列中每个值都对应环形缓冲区中的一个槽:
在这里插入图片描述
让我们看看我们如何插入一个元素:

buffer[++writeSequence % capacity] = element

我们在插入元素之前预先增加了序列。为了消费一个元素,我们做一个后增量:

element = buffer[readSequence++ % capacity]

在这种情况下,我们对序列执行后增量。使用一个元素并不会将其从缓冲区中删除,它只是保留在数组中直到被覆盖。

缓冲区空与溢出

当我们循环数组时,我们将开始覆盖缓冲区中的数据。如果缓冲区已满,我们可以选择覆盖最旧的数据,无论读取序列是否已使用它或阻止覆盖尚未读取的数据。
如果中间值或旧值(例如,商品价格)可以被覆盖,我们可以覆盖数据而无需等待数据被使用。另一方面,如果必须消耗序列中所有值(例如电子商务交易),我们应该等待(阻塞/忙碌等待),直到缓冲区有可用的插槽。
如果缓冲区的大小等于其容量,则缓冲区已满,其中其大小等于未读元素的数量:

size = (writeSequence - readSequence) + 1
isFull = (size == capacity)

在这里插入图片描述
如果写序列落后于读序列,则缓冲区为空:

isEmpty = writeSequence < readSequence

在这里插入图片描述
如果缓冲区为空,则缓冲区返回空值。

优点与缺点

环形缓冲区是一种高效的FIFO缓冲区。它使用可以预先分配的固定大小的数组,并允许高效的内存访问模式。所有缓冲区操作都是常数时间O(1),包括消耗一个元素,因为它不需要移动元素。
另一方面,确定环形缓冲区的正确大小至关重要。例如,如果缓冲区过小并且读取速度很慢,则写入操作可能会阻塞很长时间。我们可以使用动态调整大小,但它需要移动数据,我们会错过上面讨论的大部分优势。

Go的实现

在了解环形缓冲区的原理之后,我们来用Go实现这个数据结构。

结构体定义

type T string

type RingBuffer struct {
   sync.RWMutex
   data     []T
   capacity int
   read     int
   write    int
}

我们定义一个环形缓冲区结构体,其中包含值数组、数组大小,读指针和写指针。同时,它也是并发安全的。

初始化

首先,让我们定义一个使用预定义容量初始化缓冲区的构造函数:

const DefaultCapacity = 8

func NewRingBuffer(cap int) *RingBuffer {
   ring := &RingBuffer{}
   if cap < 1 {
      cap = DefaultCapacity
   }

   ring.data = make([]T, cap)
   ring.capacity = cap
   ring.read = 0
   ring.write = -1

   return ring
}

接下来,我们将实现Offer操作,在下一个可用槽处将元素插入缓冲区,并在成功时返回 true。如果缓冲区找不到空槽,则返回false,也就是说,我们不能覆盖未读取的值。

func (r *RingBuffer) Offer(t T) bool {
   if !r.IsFull() {
      next := r.write + 1
      r.data[next%r.capacity] = t
      r.write++
      return true
   }

   return false
}

因此,我们正在递增写入序列并计算数组中下一个可用插槽的索引。然后,我们将数据写入缓冲区并存储更新的写入序列。

最后,我们将实现获取并删除下一个未读元素的轮询操作。轮询操作不会删除元素,但会增加读取序列。

func (r *RingBuffer) Poll() *T {
   if !r.IsEmpty() {
      next := r.data[r.read%r.capacity]
      r.read++
      return &next
   }

   return nil
}

在这里,我们通过计算数组中的索引来读取当前读取序列的数据。然后,如果缓冲区不为空,我们将递增序列并返回值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript 入门指南(三)BOM 对象和 DOM 对象

BOM 对象 BOM 简介 BOM&#xff08;browser Object Model&#xff09;即浏览器对象模型BOM 由一系列对象组成&#xff0c;是访问、控制、修改浏览器的属性的方法BOM 没有统一的标准&#xff08;每种客户端都可以自定标准&#xff09;。BOM 的顶层是 window 对象 window 对象 …

深入解析Hadoop生态核心组件:HDFS、MapReduce和YARN

这里写目录标题 01HDFS02Yarn03Hive04HBase1&#xff0e;特点2&#xff0e;存储 05Spark及Spark Streaming关于作者&#xff1a;推荐理由&#xff1a;作者直播推荐&#xff1a; 一篇讲明白 Hadoop 生态的三大部件 进入大数据阶段就意味着进入NoSQL阶段&#xff0c;更多的是面向…

代码随想录阅读笔记-二叉树【二叉树的所有路径】

题目 给定一个二叉树&#xff0c;返回所有从根节点到叶子节点的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 思路 这道题目要求从根节点到叶子的路径&#xff0c;所以需要前序遍历&#xff0c;这样才方便让父节点指向孩子节点&#xff0c;找到对应的路径。 在这道…

【CSS】基础选择器

目录 标签选择器 id选择器 类选择器 CSS的编写地点&#xff1a; 标签选择器 说明&#xff1a;标签选择器实际上就是HTML标签元素&#xff08;可以是任何HTML元素&#xff09;&#xff0c;用来改变一个指定标签的样式 示例&#xff1a; <style type"text/css"…

QQ邮箱SMTP发送邮件时要注意哪些安全设置?

QQ邮箱SMTP发送邮件的步骤&#xff1f;如何配置QQ邮箱服务器&#xff1f; 在使用QQ邮箱SMTP发送邮件时&#xff0c;安全设置是至关重要的一环。不当的安全设置不仅可能导致邮件发送失败&#xff0c;还可能使你的账户面临安全风险。下面&#xff0c;AokSend就来详细探讨一下QQ邮…

基于单片机16位智能抢答器设计

**单片机设计介绍&#xff0c;基于单片机16位智能抢答器设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机16位智能抢答器设计是一个结合了单片机技术、显示技术、按键输入技术以及声音提示技术的综合性项目。其设计…

脑机辅助推导算法

目录 一&#xff0c;背景 二&#xff0c;华容道中道 1&#xff0c;问题 2&#xff0c;告诉脑机如何编码一个正方形格子 3&#xff0c;让脑机汇总信息 4&#xff0c;观察图&#xff0c;得到启发式算法 5&#xff0c;根据启发式算法求出具体解 6&#xff0c;可视化 一&am…

苹果App审核大揭秘

苹果上架要求是苹果公司对于提交应用程序到苹果商店上架的要求和规定。这些要求主要是为了保证用户体验、应用程序的质量和安全性。以下是苹果上架要求的详细介绍&#xff1a;1. 应用程序的内容和功能必须符合苹果公司的规 苹果上架要求是苹果公司对于提交应用程序到苹果商店上…

u盘不显示盘符怎么办,u盘不显示盘符

我们经常使用电脑,难免会遇到各种问题,其中U盘不显示盘盘符也是常见的一种。用u盘插入电脑usb接口后,却识别不出u盘,而且更换usb接口以后还是没有u盘盘符,这可怎么用呢?针对此问题,极客狗整理了两个处理方法,接下来带小伙伴一起看看u盘不显示盘符怎么办。遇到同样问题的…

Python数据结构实验 查找实验(一)

一、实验目的 1&#xff0e;熟悉查找的基本概念&#xff0c;包括静态查找表和动态查找表、内查找和外查找之间的差异以及平均查找长度等&#xff1b; 2&#xff0e;掌握线性表上的各种查找算法&#xff0c;包括顺序查找、折半查找和分块查找的基本思路、算法实现和查找效率等…

游戏引擎中的声音系统

一、声音基础 1.1 音量 声音振幅的大小 压强p&#xff1a;由声音引起的与环境大气压的局部偏差 1.2 音调 1.3 音色 1.4 降噪 1.5 人的听觉范围 1.6 电子音乐 将自然界中连续的音乐转换成离散的信号记录到内存中 采样 - 量化 - 编码 香农定理&#xff1a;采样频率是信…

云原生技术精选:探索腾讯云容器与函数计算的最佳实践

文章目录 写在前面《2023腾讯云容器和函数计算技术实践精选集》深度解读案例集特色&#xff1a;腾讯云的创新实践与技术突破精选案例分析——Stable Diffusion云原生部署的最佳实践精选集实用建议分享总结 写在前面 在数字化转型的浪潮下&#xff0c;云计算技术已成为企业运营…

shell脚本发布docker-nginx vue2 项目示例

docker、git、node.js安装略过。 使git pull或者git push不需要输入密码操作方法 nginx安装在docker容器里面&#xff0c;参见&#xff1a;https://blog.csdn.net/HSJ0170/article/details/128631155 姊妹篇&#xff08;宿主机nginx&#xff0c;非docker-nginx&#xff09;&am…

Real-data WRF | setup and run and experiment

前言 Parent Model 用于初始化和边界条件的网格数据 GFS/FNL、NAM、RAP/HRRR、重新分析&#xff08;NARR、CFSR、NNRP、ERA-interim、ERA5 等&#xff09;、其他 WRF 运行 WPS WRF 预处理系统&#xff08;由 geogrid、ungrib 和 metgrid 程序组成&#xff09; WRF 模拟几…

【Linux多线程】生产者消费者模型

【Linux多线程】生产者消费者模型 目录 【Linux多线程】生产者消费者模型生产者消费者模型为何要使用生产者消费者模型生产者消费者的三种关系生产者消费者模型优点基于BlockingQueue的生产者消费者模型C queue模拟阻塞队列的生产消费模型 伪唤醒情况&#xff08;多生产多消费的…

【手册】——mq延迟队列

目录 一、背景介绍二、思路&方案三、过程1.项目为啥用延迟队列&#xff1f;2.项目为啥用三方延迟队列&#xff1f;3.项目中为啥用rabbitmq延迟队列&#xff1f;4.rabbitmq延迟队列的安装5.rabbitmq的延迟队列配置方式5.1.exchange配置5.2.queues配置5.3.exchange和queues的…

文件操作(1)【文件打开和关闭】【文件的顺序读写(各种函数)】【sprintf和sscanf的理解】

一.什么是文件&#xff1f; 在程序设计中我们一般谈的文件有两种&#xff1a;程序文件和数据文件 1.程序文件 程序文件是包含计算机程序代码的文件。它通常包含一系列指令和算法&#xff0c;用于执行特定的任务或实现特定的功能。程序文件可以由不同的编程语言编写&#xff…

【C语言环境】Sublime中运行C语言时MinGW环境的安装

要知道&#xff0c;GCC 官网提供的 GCC 编译器是无法直接安装到 Windows 平台上的&#xff0c;如果我们想在 Windows 平台使用 GCC 编译器&#xff0c;可以安装 GCC 的移植版本。 目前适用于 Windows 平台、受欢迎的 GCC 移植版主要有 2 种&#xff0c;分别为 MinGW 和 Cygwin…

【Python】——变量名的命名规则

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

Linux shell编程学习笔记42:md5sum

0 前言 前几天在国产电脑上遇到一个问题&#xff0c;先后接到两个文件&#xff0c;如何判断这两个文件内容是否相同&#xff1f; 如果是在Windows系统&#xff0c;可以用fc命令&#xff0c;或者用我自己写的FileInfo&#xff0c;提取两个文件有MD5、SHA1、CRC32值进行比较来判…