數組(ArrayPool數組池、Span結構)

前言

  若是須要使用相同的類型的多個對象,就可使用集合和數組,這一節主要講解數組,其中會重點涉及到Span<T>結構和ArrayPool數組池。咱們也會先涉及到簡單的數組、多維數組、鋸齒數組、Array類。html

簡單的數組、多維數組、鋸齒數組

  簡單的數組介紹c#

  數組的聲明:數組

Int [] myArray;

  初始化:性能

myArray=new int[4];

  還能夠:學習

Int [] myArray=new int []{1,2,3,4};

  訪問數組:優化

myArray[0];

 

  多維數組介紹spa

  通常的數組(也稱一維數組)是用一個數字來索引,多維數組用兩個或兩個以上的數字進行索引。3d

  聲明多維數組時中間以,隔開,咱們下面聲明一個二維數組。code

 int  [,]  twodim=new  int [3,3] int[,] twodim = { { 1,2,3}, { 4,5,6}, { 7,8,9} };

 

  一個三維數組。htm

int[,,] threedim = { { { 1,2},{ 3,4} }, {{ 5,6},{ 7,8} }, { { 9,10},{ 11,12} } }; Console.WriteLine(threedim[0,1,1]);

 

  鋸齒數組

  二維數組圖形:

 

  鋸齒數組

 

  在聲明鋸齒數組的時候要依次放置左右括號。在初始化鋸齒數組時,只對第一對方括號中設置該數組包含的行數,定義各行中元素個數的第二個方括號設爲空,由於這類數組的每一行包含不一樣的元素個數。

   int[][] jagged = new int[3][]; jagged[0] = new int[2] { 1, 2 }; jagged[1] = new int[4] { 3, 4, 5, 6 }; jagged[2] = new int[3] { 7, 8, 9 };

 

Array類

  建立數組:

Array intArray1 = Array.CreateInstance(typeof(int), 5); for (int i = 0; i < intArray1.Length; i++) { intArray1.SetValue(33, i);   }

  上面這段代碼,描述了Array數組的建立以及設置值。CreateInstance()方法第一個參數爲元素的類型,第二個參數爲定義數組的大小。SetValue()方法設置值第一個參數爲設置IDE值,第二個參數爲設置的索引。

  複製數組:

int[] intArray1 = { 1,2}; int[] intArray2 = (int[])intArray1.Clone();

  由於數組是引用類型的,因此將一個數組的變量賦予另外一個數組變量,就會獲得兩個引用同一個數組的變量,這是使用的是Clone()方法建立數組的淺表副本。使用Copy()方法也能夠建立淺表副本,Clone()方法會建立一個數組,而Copy()方法必須傳遞階數相同且有足夠元素的已有數組。

  排序:

class Program { static void Main(string[] args) { int[] list = { 34, 72, 13, 44, 25, 30, 10 }; Console.Write("原始數組: "); foreach (int i in list) { Console.Write(i + " "); } Console.WriteLine(); // 逆轉數組
 Array.Reverse(list); Console.Write("逆轉數組: "); foreach (int i in list) { Console.Write(i + " "); } Console.WriteLine(); // 排序數組
 Array.Sort(list); Console.Write("排序數組: "); foreach (int i in list) { Console.Write(i + " "); } Console.WriteLine(); } }

 

  輸出:

原始數組: 34 72 13 44 25 30 10 逆轉數組: 10 30 25 44 13 72 34 排序數組: 10 13 25 30 34 44 72

  在上述方法中Array.Sort()方法實現了數組的排序,而Array.Reverse()實現了數組的逆轉 。

ArrayPool數組池

  接下來重點來了,本文的重點一,ArrayPool數組池。若是一個應用須要建立和銷燬許多的數組,垃圾收集器就要花費不少的功夫來作這些工做,爲了較少垃圾收集器的工做,這裏咱們可使用ArrayPool類來使用數組池。ArrayPool管理一個數組池,數組能夠再這裏租借內存,而且返回到這裏。須要引用using System.Buffers;

  建立數組池:

ArrayPool<int> arrayPool = ArrayPool<int>.Create(maxArrayLength:40000, maxArraysPerBucket: 10);

  maxArrayLength的默認值是1024*10224字節(數組的長度),maxArraysPerBucket默認值是50(數組的數量)。

  這裏還可使用如下方法來使用預約義的共享池。

ArrayPool<int> sharePool = ArrayPool<int>.Shared;

  下面咱們就一塊兒看看如何去使用這個數組池吧:

 

class Program { static void Main(string[] args) { //定義數組池
            ArrayPool<int> arrayPool = ArrayPool<int>.Create(maxArrayLength: 10000, maxArraysPerBucket: 10); //定義使用數組的長度
            int arrayLenght = 5; int[] array = arrayPool.Rent(arrayLenght); //輸出數組的長度
            Console.WriteLine($"定義數組長度:{arrayLenght},實際數組長度:{array.Length}"); //對數組進行賦值
            array[0] = 0; array[1] = 1; array[2] = 2; array[3] = 3; array[4] = 4; //輸出數組的值
            foreach (var item in array) { Console.WriteLine(item); } //將內存返回給數組池,clearArray設置True清除數組,下次調用時爲空,設置False,保留數組,下次調用仍是如今的值
            arrayPool.Return(array, clearArray: true); foreach (var item in array) { Console.WriteLine(item); } } }

 

  在上面事例中,咱們使用Rent()方法請求池中的內存,Rent方法返回一個數組,其中至少包含所請求的元素個數。返回的數組可能會用到更多的內存,池中最少的請求爲16個元素,緊接着是32,64,128以此類推。因此在上述例子中咱們請求的長度爲5,可是實際使用的元素個數爲16個,多餘的將根據類型對其賦值0或者null。

  咱們使用Return()方法將數組返回到池中,這裏使用了一個可選參數clearArray,指定是否清除該數組,不清除的話下一個從池中租用這個數組的人能夠讀取到其中的數據。清除數據能夠避免這種狀況,可是會消耗更多的CPU時間。

Span<T>

  Span<T>介紹

  爲了快速訪問託管或非託管的連續內存,可使用Spam<T>結構。一個可使用Span<T>結構的例子就是數組,Span<T>結構在後臺保存在連續的內存中,另外一個例子就是長字符串。

  使用Span<T>結構,能夠直接訪問數組元素。數組的元素沒有複製,可是它們能夠直接調用,而且比複製還快。

class Program { static void Main(string[] args) { int[] arr1 = { 3, 5, 7, 9, 11, 13, 15, 18, 19 }; var span1 = new Span<int>(arr1); span1[1] = 11; Console.WriteLine(arr1[1]); } }

  輸出:

 

 

  這裏將建立的arr1數組傳遞給Span<T>,同時Span<T>類型提供了一個索引器,這裏直接修改span1的第二個值,而後再輸出arr1數組中的第二個值,也是被其修改過得值。

  Span<T>切片

  Span<T>它一個強大的特性是,可使用它訪問數組的部分或者切片,使用切片的時候不會複製數組元素,他們是從Span中直接訪問的。下面代碼介紹了建立切片的兩種方法:

class Program { static void Main(string[] args) { //定義簡單的數組
            int[] arr2 = { 3, 5, 7, 9, 11, 13, 15, 18, 19, 20, 30, 40, 50, 60 }; //Span<T>對數組進行切片,訪問arr2數組,從第三個開始,取長度6個的一個數組。
            var span3 = new Span<int>(arr2, start: 3, length: 6); //輸出切片中的值
            foreach (var item in span3) { Console.WriteLine(item); } Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine(""); //對span3進行切片處理,從第二個開始,去長度4個的一個數組
            var span4 = span3.Slice(start: 2, length: 4); foreach (var item in span4) { Console.WriteLine(item); } } }

 

  輸出:

 

 

  使用Span<T>改變值

  前面介紹瞭如何使用Span<T>的索引器,更改數組的元素,下面介紹的將會有更多的選項,關於修改元素的值及複製。

class Program { static void Main(string[] args) { //定義簡單的數組
            int[] arr = { 3, 5, 7, 9, 11, 13, 15, 18, 19, 20, 30, 40, 50, 60 }; //將數組傳遞給span
            var span = new Span<int>(arr); var span2 = new Span<int>(arr); //對span進行切片處理,從第四個開始
            var span3 = span.Slice(start: 4 ); //調用clear方法,用0填充span3
 span3.Clear(); foreach (var item in span3) { Console.WriteLine("span3的值:"+item); } Console.WriteLine("span3的長度:"+span3.Length); //建立新的切片span4,從span2開始,長度3
            Span<int> span4 = span2.Slice(start: 3, length: 3); //調用Fill方法,用傳入的值填充span4
            span4.Fill(42); foreach (var item in span4) { Console.WriteLine("span4的值"+item); } Console.WriteLine("span4的長度"+span4.Length); //將span4複製給span,複製失敗
 span4.CopyTo(span); //將span複製給span3 複製失敗
            if (!span.TryCopyTo(span3)) { Console.WriteLine("複製不了"); } } }

 

  輸出:

 

 

  上面事例中,顯示調用clear()方法,該方法用0填充Span,而後調用了Fill()方法,該方法用傳遞給Fill方法的值來填充Span,同時也能夠將一個Span<T>複製給另外一個Span<T>,這裏先是採用的CopyTo,在這個方法中,若是另外一個目標span不夠大,就會複製失敗,這裏可使用TryCopyTo來優化此功能,若是目標不夠大,將會返回false。以此來判斷是否複製成功。上面例子中span4長度爲3,而span長度爲14,這裏是複製成功了,而後其下面的操做,由於span3的長度是10,span複製給span3失敗了。由於span3不夠大。

  上面事例中提供了改變值的一些方法,當咱們不須要對值進行改變,只須要對數組進行讀訪問的時候,咱們可使用ReadOnlySpan<T>。這裏定義了只讀的Span

 ReadOnlySpan<int> readonlySpan = new ReadOnlySpan<int>(arr);

 

總結

  在本篇文章中,重點介紹了ArrayPool數組池和Span<T>結構,經過使用數組池,來下降數組建立和銷燬時消耗的性能,減小垃圾回收器的工做,使用Span<T>能夠快速的訪問託管及非託管代碼,建立切片來對數組和長字符串進行必定的操做。更加高效的操做數組。

 

  青少年是一個美好而又是一去不可再得的時期,是未來一切光明和幸福的開端。——加裏寧

  個人博客即將同步至騰訊雲+社區,邀請你們一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=2n1gp5jweqww4

 

 


 

                      c#基礎知識詳解系列

 

  歡迎你們掃描下方二維碼,和我一塊兒學習更多的C#知識 

  

相關文章
相關標籤/搜索