每天5分钟用C#学习数据结构(14)队列 Part 3

每天5分钟用C#学习数据结构(14)队列 Part 3

每天5分钟,学习数据结构


介绍了队列的链式存储实现及循环队列要点,本篇作为队列部分的完结篇,会介绍一下队列的常见应用场景,然后带你看看.NET中的队列Queue的实现要点。


1 队列的应用场景

队列在实际开发中应用得非常广泛,这里来看看在互联网系统中常见的一个应用场景:消息队列。“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。消息被发送到队列中,“消息队列”是在消息的传输过程中保存消息的容器。

在目前广泛的Web应用中,都会出现一种场景:在某一个时刻,网站会迎来一个用户请求的高峰期(比如:淘宝的双十一购物狂欢节,12306的春运抢票节等),一般的设计中,用户的请求都会被直接写入数据库或文件中,在高并发的情形下会对数据库服务器或文件服务器造成巨大的压力,同时呢,也使响应延迟加剧。这也说明了,为什么我们当时那么地抱怨和吐槽这些网站的响应速度了。当时2011年的京东图书促销,曾一直出现在购物车中点击“购买”按钮后一直是“Service is too busy”,其实就是因为当时的并发访问量过大,超过了系统的最大负载能力。当然,后边,刘强东临时购买了不少服务器进行扩展以求增强处理并发请求的能力,还请了信息部的人员“喝茶”,现在京东已经是超大型的网上商城了,我也有许多同学在京东成都研究院工作了。

每天5分钟用C#学习数据结构(14)队列 Part 3

从京东当年的“Service is too busy”不难看出,高并发的用户请求是网站成长过程中必不可少的过程,也是一个必须要解决的难题。在众多的实践当中,除了增加服务器数量配置服务器集群实现伸缩性架构设计之外,异步操作也被广泛采用。而异步操作中最核心的就是使用消息队列,通过消息队列,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务,改善网站系统的性能。在京东之类的电子商务网站促销活动中,合理地使用消息队列,可以有效地抵御促销活动刚开始就开始大量涌入的订单对系统造成的冲击。

每天5分钟用C#学习数据结构(14)队列 Part 3


2 .NET中的Queue

虽然队列有顺序存储和链式存储两种存储方式,但在.NET中使用的是顺序存储,它所对应的集合类是System.Collections.Queue与System.Collections.Generic.Queue,两者结构相同,不同之处仅在于前者是非泛型版本,后者是泛型版本的队列。它们都属于循环队列,这里我们通过Reflector来重点看看泛型版本的实现。

每天5分钟用C#学习数据结构(14)队列 Part 3

我们来看看在.NET中的Queue是如何实现入队和出队操作的。首先来看看入队Enqueue方法:

<code>public void Enqueue(T item)
{
if (this._size == this._array.Length)
{
int capacity = (this._array.Length * 200) / 100;
if (capacity < (this._array.Length + 4))
{
capacity = this._array.Length + 4;
}
this.SetCapacity(capacity);
}
this._array[this._tail] = item;
this._tail = (this._tail + 1) % this._array.Length;
this._size++;
this._version++;
}/<code>

可以看出,与我们之前所实现的Enqueue方法类似,首先判断了队列是否满了,如果满了则进行扩容,不同之处在我们是直接*2倍,这里是在原有容量基础上+4。由于是循环队列,对tail指针使用了%运算来确定下一个入队位置。


我们再来看看Dequeue方法是怎么实现的:

<code>public T Dequeue()
{
if (this._size == 0)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyQueue);
}
T local = this._array[this._head];

this._array[this._head] = default(T);
this._head = (this._head + 1) % this._array.Length;
this._size--;
this._version++;
return local;
}/<code>

同样,与之前类似,不同之处在于判断队空时这里直接抛了异常,其次由于是循环队列,head指针也使用了%运算来确定下一个出队元素的位置。


3 小结

本文介绍了队列的常见应用场景:消息队列,然后带你看了.NET Framework中自带的队列Queue的源码实现要点。

从下一篇开始,我们就正式告别线性表,进入树与二叉树的部分!


程杰,《大话数据结构》

陈广,《数据结构(C#语言描述)》

段恩泽,《数据结构(C#语言版)》


往期精彩


每天5分钟用C#学习数据结构(14)队列 Part 3

专栏:EdisonTalk(爱迪生说)

本文作者EdisonZhou,架构师,阿里云MVP,博客园"推荐博客"博主(Top10),Scrum联盟认证CSM,.NET Core实践者与布道师,爱好阅读与分享。

本文首发于EdisonZhou的公众号“恰童鞋骚年”,欢迎关注,第一时间获得更多内容分享。


分享到:


相關文章: