本文將使用一個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;
}
相關的話題,后續補充。
