sv队列和动态数组的区别_走进C#并发队列ConcurrentQueue的内部世界—NET Framework篇...

本文详细介绍了C#中的并发队列ConcurrentQueue,基于.NET Framework 4.8源码,探讨其存储结构(数组+链表的组合)、初始化、入队、出队操作以及线程安全性。ConcurrentQueue使用Segment(段)存储,每个段是固定大小的数组,通过链表连接,通过SpinWait和原子操作保证线程安全。
摘要由CSDN通过智能技术生成

决定从这篇文章开始,开一个读源码系列,不限制平台语言或工具,任何自己感兴趣的都会写。前几天碰到一个小问题又读了一遍ConcurrentQueue的源码,那就拿C#中比较常用的并发队列ConcurrentQueue作为开篇来聊一聊它的实现原理。

话不多说,直奔主题。

要提前说明下的是,本文解析的源码是基于.NET Framework 4.8版本,地址是:https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentQueue.cs本来是打算用.NET Core版本的,但是找了一下竟然没找到:https://github.com/dotnet/runtime/tree/master/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent不知道是我找错位置了还是咋回事,有知道的大佬告知一下。不过我觉得实现原理应该类似吧,后面找到了我对比一下,不同的话再写一篇来分析。

带着问题出发

如果是自己实现一个简单的队列功能,我们该如何设计它的存储结构呢?一般来说有这两种方式:数组或者链表,先来简单分析下。

我们都知道,数组是固定空间的集合,意味着初始化的时候要指定数组大小,但是队列的长度是随时变化的,超出数组大小了怎么办?这时候就必须要对数组进行扩容。问题又来了,扩容要扩多少呢,少了不够用多了浪费内存空间。与之相反的,链表是动态空间类型的数据结构,元素之间通过指针相连,不需要提前分配空间,需要多少分配多少。但随之而来的问题是,大量的出队入队操作伴随着大量对象的创建销毁,GC的压力又变得非常大。事实上,在C#的普通队列Queue类型中选择使用数组进行实现,它实现了一套扩容机制,这里不再详细描述,有兴趣的直接看源码,比较简单。

回到主题,要实现一个高性能的线程安全队列,我们试着回答以下问题:

  • 存储结构是怎样的
  • 如何初始化(初始容量给多少比较好?)
  • 常用操作(入队出队)如何实现
  • 线程安全是如何保证的

存储结构

通过源码可以看到ConcurrentQueue采用了数组+链表的组合模式,充分吸收了2种结构的优点。

具体来说,它的总体结构是一个链表,链表的每个节点是一个包含数组的特殊对象,我们称之为Segment(段或节,原话是a queue is a linked list of small arrays, each node is called a segment.),它里面的数组是存储真实数据的地方,容量固定大小是32,每一个Segment有指向下一个Segment的的指针,以此形成链表结构。而队列中维护了2个特殊的指针,他们分别指向队列的首段(head segment)和尾段(tail segment),他们对入队和出队有着重要的作用。用一张图来解释队列的内部结构:

3a10f48abf2769dc361578181fbc0e6f.png

嗯,画图画到这里突然联想到,搞成双向链表的话是不是就神似B+树的叶子节点?技术就是这么奇妙~

段的核心定义为:

/// /// private class for ConcurrentQueue. /// 链表节点(段)/// private class Segment{    //实际存储数据的容器    internal volatile T[] m_array;    //存储对应位置数据的状态,当数据的对应状态位标记为true时该数据才是有效的    internal volatile VolatileBool[] m_state;    //下一段的指针    private volatile Segment m_next;    //当前段在队列中的索引    internal readonly long m_index;    //两个位置指针    p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值