本文将使用一个gitHub开源的组件技术来实现这个功能

github地址:https://github.com/dathlin/HslCommunication                             如果喜欢可以star或是fork,还可以打赏支持。

官网地址:http://www.hslcommunication.cn/         打赏请认准官网

场景需求


我们会有对缓存数据的需求。C#本身提供了固定长度的数组 T[]  , 可变长度的List<T>  当然还有先入先出,后入后出的队列。

通常实际中,我们需要维护一个缓存的数组队列,比如一个int数组,长度为1000个,当我们读取到数据后,需要往里面添加数据,然后所有的数据都是往左挪动。最后这个数据是线程安全的操作。

第一种写法,就是循环挪动数据:

int[] buffer = new int[1000];

                hybirdLock.Enter( );

                for (int j = 0; j < buffer.Length - 1; j++)
{
buffer[j] = buffer[j + 1];
} buffer[999] = 100; hybirdLock.Leave( );

第二种写法,批量挪动数据

int[] buffer = new int[1000];

                hybirdLock.Enter( );

                int[] newbuffer = new int[1000];
Array.Copy( buffer, 0, newbuffer, 0, 999 );
newbuffer[999] = 100;
buffer = newbuffer; hybirdLock.Leave( );

  

第三种写法,就是List泛型类,和先入先出的用法差不多

int[] buffer = new int[1000];
List<int> list = new List<int>( buffer ); hybirdLock.Enter( ); list.Add( 100 );
list.RemoveAt( 0 ); hybirdLock.Leave( );

  

第四种写法:SharpList<T> 类型实现

            SharpList<int> sharpList = new SharpList<int>( 1000, true );
sharpList.Add( 1000 );

初步对比,SharpList代码上更加精简。因为内置了线程安全,自动挪动数据。

上述代码我们定义了一个长度为1000的int类型的数组对象。实例化之后,其本身就是一个1000个长度的 int[] 数组,当 Add(100);时,最右侧就多了一个100的数据。

SharpList<T> 提供了几个方法来方便快捷的操作数据。比如根据索引为访问:

int value = sharpList[0];  // 得到0
int value2 = sharpList[999]; // 得到100 int[] tmp = sharpList.ToArray(); // 得到数组数据的副本。[0,,,,,,,,,,999]

  

当新增数据的时候,也支持批量的新增。

性能对比


我们将上述的四种方式各自运行100W次,查看下各自的性能差异,具体运行时间取决于cpu型号,内存,等因数,此处仅仅是一个参考。

            SimpleHybirdLock hybirdLock = new SimpleHybirdLock( );

            int[] buffer = new int[1000];
DateTime start = DateTime.Now;
for (int i = 0; i < 1000000; i++)
{
hybirdLock.Enter( ); for (int j = 0; j < buffer.Length - 1; j++)
{
buffer[j] = buffer[j + 1];
} buffer[999] = i; hybirdLock.Leave( );
} Console.WriteLine( (DateTime.Now - start).TotalMilliseconds ); start = DateTime.Now;
for (int i = 0; i < 1000000; i++)
{
hybirdLock.Enter( ); int[] newbuffer = new int[1000];
Array.Copy( buffer, 0, newbuffer, 0, 999 );
newbuffer[999] = i;
buffer = newbuffer; hybirdLock.Leave( );
} Console.WriteLine( (DateTime.Now - start).TotalMilliseconds ); List<int> list = new List<int>( buffer );
start = DateTime.Now;
for (int i = 0; i < 1000000; i++)
{
hybirdLock.Enter( ); list.Add( i );
list.RemoveAt( 0 ); hybirdLock.Leave( );
} Console.WriteLine( (DateTime.Now - start).TotalMilliseconds ); SharpList<int> sharpList = new SharpList<int>( 1000, true );
start = DateTime.Now;
for (int i = 0; i < 1000000; i++)
{
sharpList.Add( i );
}
Console.WriteLine( (DateTime.Now - start).TotalMilliseconds ); int[] data = sharpList.ToArray( ); Console.ReadLine( );

  

我们跑三次,对比结果。

我们看到SharpList<T> 类仅仅消耗了37ms,完成了100W次数据的新增和挪动。

为什么会有那么大的性能差异呢?就要深入源代码查看了。

深度剖析


超高的性能的本质在于减少大块的数据移动,先内部实例化一个远比需求还大的多的数据对象

array = new T[capacity + count];

  

当有数据新增进来的时候,实际不需要移动

        /// <summary>
/// 新增一个数据值
/// </summary>
/// <param name="value">数据值</param>
public void Add( T value )
{
hybirdLock.Enter( ); if(lastIndex < (capacity + count))
{
array[lastIndex++] = value;
}
else
{
// 需要重新挪位置了
T[] buffer = new T[capacity + count];
Array.Copy( array, capacity, buffer, 0, count );
array = buffer;
lastIndex = count;
} hybirdLock.Leave( );
}

  先进行自然的赋值,这时的性能就非常快了,然后提高游标的索引。当缓存都不够时,再去复制挪动一次数据。

当然,当要获取数据时,就需要进行根据当前的活动游标进行获取到正确的数据。

        /// <summary>
/// 获取数据的数组值
/// </summary>
/// <returns>数组值</returns>
public T[] ToArray( )
{
T[] result = null;
hybirdLock.Enter( ); if (lastIndex < count)
{
result = new T[lastIndex];
Array.Copy( array, 0, result, 0, lastIndex );
}
else
{
result = new T[count];
Array.Copy( array, lastIndex - count, result, 0, count );
}
hybirdLock.Leave( );
return result;
}

  

相关的话题,后续补充。

C# 高性能的数组 高性能数组队列实战 HslCommunication的SharpList类详解的更多相关文章

  1. 最佳实战Docker持续集成图文详解

    最佳实战Docker持续集成图文详解 这是一种真正的容器级的实现,这个带来的好处,不仅仅是效率的提升,更是一种变革:开发人员第一次真正为自己的代码负责——终于可以跳过运维和测试部门,自主维护运行环境( ...

  2. shell编程系列23--shell操作数据库实战之mysql命令参数详解

    shell编程系列23--shell操作数据库实战之mysql命令参数详解 mysql命令参数详解 -u 用户名 -p 用户密码 -h 服务器ip地址 -D 连接的数据库 -N 不输出列信息 -B 使 ...

  3. Redis实战 | 5种Redis数据类型详解

    我们知道Redis是目前非常主流的KV数据库,它因高性能的读写能力而著称,其实还有另外一个优势,就是Redis提供了更加丰富的数据类型,这使得Redis有着更加广泛的使用场景.那Redis提供给用户的 ...

  4. PHP数组的交集array_intersect(),array_intersect_assoc(),array_inter_key()函数详解

    求两个数组的交集问题可以使用 array_intersect(),array_inersect_assoc,array_intersect_key来实现,其中 array_intersect()函数是 ...

  5. 遍历查找集合或者数组中的某个元素的值 java代码 详解 Android开发

    import java.util.Scanner; public class Test21 { public static void main(String[] args) { //定义并初始化数组 ...

  6. Kafka高性能揭秘:sequence IO、PageCache、SendFile的应用详解

    大家都知道Kafka是将数据存储于磁盘的,而磁盘读写性能往往很差,但Kafka官方测试其数据读写速率能达到600M/s,那么为什么Kafka性能会这么高呢? 首先producer往broker发送消息 ...

  7. Hadoop实战之二~ hadoop作业调度详解(1)

    对Hadoop的最感兴趣的地方,也就在于Hadoop的作业调度了,在正式介绍如何搭建Hadoop之前,深入理解一下Hadoop的作业调度很有必要.我们不一定能用得上Hadoop,但是如果理通顺Hado ...

  8. reactjs入门到实战(五)---- props详解

    1>>>基础的props使用     不可修改父属性    getDefaultProps   对于外界/父组件的属性值,无法直接修改,它是只读的. <script type= ...

  9. reactjs入门到实战(四)---- state详解

    this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性. 组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开 ...

随机推荐

  1. 智能边缘计算,让IoT有大智慧

    丹棱君有话说:什么是智能边缘计算(Edge Computing)?别着急,它可是与你与我都有着千丝万缕的联系.物联网(IoT)的概念早已飞入寻常百姓家,在日常生活中的许多场景发挥着“智能”作用.比如, ...

  2. 性能测试 tps持续走低,响应时间持续增加,瓶颈分析

    吞吐量图如上 响应时间图如上 自身压测的机器,资源使用率并没有饱和 服务器,top命令下看到load average的值很低,本身是4核的server. 每个核的CPU使用率也极低,空闲cpu占95+ ...

  3. shell 命令行光标跳转快捷键和history的用法

    Ctrl+a: 跳到命令行首 Ctrl+e: 跳到命令行尾 Ctrl+u: 删除光标至命令行首的内容 Ctrl+k: 删除光标至命令行尾的内容 Ctrl+<- 跳到前一个单词首部 Ctrl+-& ...

  4. 很火的Java题——判断一个整数是否是奇数

    完成以下代码,判断一个整数是否是奇数: public boolean isOdd(int i) 看过<编程珠玑>的人都知道这道题的答案和其中极为简单的道理. 最普遍的风格,如下: 这个函数 ...

  5. 使用tk.mybatis快速开发curd

    使用mybatis已经是可以快速开发程序了,对于单表的curd似乎是一种可抽象的结果,下面介绍tk.mybatis的使用方式. maven引用 我使用的是这个版本,所以相关功能介绍也是这个版本. 使用 ...

  6. C++指针详解(转)

    指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占 ...

  7. C++学习笔记(二)——交换函数(swap)

    这次我们要透过一个简单的函数swap深入理解函数传参的本质以及在C++中如何选择传参方式. 先来看第一段程序: void swap(int x, int y) { int temp = y; y = ...

  8. Style、ControlTemplate 和 DataTemplate 触发器

    本文摘要:    1:属性触发器:    2:数据触发器:    3:事件触发器: Style.ControlTemplate 和 DataTemplate 都有触发器集合.    属性触发器只检查W ...

  9. 1月5日 对象Object, 含过去看的英文档的总结链接

    Object 也是一种数据类型,可以有属性,有method. 反之,在Ruby中,每一种数据类型都是Object.如String,Integer,Float,Array,Hash. IN Ruby e ...

  10. hdu3374 kmp+最小表示法

    Give you a string with length N, you can generate N strings by left shifts. For example let consider ...