由於某段程序的須要,我須要將一個long數組,不斷地填充數據,而後用完了以後又要清空裏面的數據,以便再次填充。因爲調用及其頻繁,因此我很在乎清除數據的性能。windows
如下程序都是基於下面的測試代碼完成:數組
using System; using System.Diagnostics; using System.Numerics; namespace FillTest { class Program { static void Main(string[] args) { var array = new long[2515]; var Empty = new long[2515]; Do(() => { Fill(array, 0L); } , "Fill"); Console.ReadLine(); } static void Fill(long[] array,long value) { for (int i = 0; i < array.Length; i++) { array[i] = value; } } static void Do(Action action,string name) { var wathch = Stopwatch.StartNew(); for (int i = 0; i < 1000000; i++) { action(); } wathch.Stop(); Console.WriteLine(name + " 耗時:" + wathch.Elapsed.ToString()); } } }
一般的,最簡單的辦法就像上面的代碼那樣,來個循環就能夠了。性能
在個人機器中(i5 6500@3.2GHz 、16GB、 Release、 .net core 二、 windows 10),Fill版本消耗1.3秒。測試
我不確認此代碼執行時是否使用了SIMD指令,因此我又編寫了一個版本:優化
static void Fill2(long[] array,long value) { var i = 0; var end = array.Length - 1; while (i < end) { array[i] = value; array[i + 1] = value; i += 2; } if((array.Length % 2) == 1){ array[array.Length - 1] = value; } }
我竟然發現,僅僅消耗了1.0秒,難道.net默認不會優化這個代碼?spa
有人會問,你爲何不調用Array自帶的Fill方法呢?我嘗試調用了,遺憾的是,同樣是1.3秒,和個人第一個版本系統。看樣子寫核心代碼的人偷懶了。哈哈.net
網上其實可以查到一些討巧的手法,例如使用一個靜態的數組,內部都是0,當須要填充某個數據時,將這個靜態數組複製到你的數組同樣起到賦值的做用。例如:pwa
Empty.CopyTo(array, 0);
這個版本居然直接達到 0.56秒,幾乎翻兩倍,的確是個好辦法。code
在我認爲CopyTo是最快的方法時,我忽然感受個人第二個實現,是否是沒有真正用到SIMD,由於個人印象中,SIMD是很是很是快的,應該不止上升那麼一點點。對象
因此我搬出了Vector對象,我是這麼幹的。
static void Fill3(long[] array,long value) { Vector<long> v = new Vector<long>(value); var i = 0; var end = array.Length - 3; while (i < end) { v.CopyTo(array, i); i += 4; } if ((array.Length % 4) == 3) { array[array.Length - 3] = value; array[array.Length - 2] = value; array[array.Length - 1] = value; }else if ((array.Length % 4) == 2) { array[array.Length - 2] = value; array[array.Length - 1] = value; } else if ((array.Length % 4) == 1) { array[array.Length - 1] = value; } }
速度提升到 0.36秒。
因此性能無界限,有沒有更快的辦法呢?
一些其餘的嘗試,但都不理想。
static unsafe void Fill4(long[] array, long value) { fixed (Int64* destinationBase = array) { for (int g = 0; g < array.Length; g++) { destinationBase[g] = value; } } }//1.2秒 static void Fill5(long[] array, long value) { Vector<long> v = new Vector<long>(value); var i = 0; var end = array.Length - 3; while (i < end) { array[i + 3] = array[i + 2] =array[i + 1] = array[i] = value; //array[i+1] = value; //array[i+2] = value; //array[i+3] = value; i += 4; } if ((array.Length % 4) == 3) { array[array.Length - 3] = value; array[array.Length - 2] = value; array[array.Length - 1] = value; } else if ((array.Length % 4) == 2) { array[array.Length - 2] = value; array[array.Length - 1] = value; } else if ((array.Length % 4) == 1) { array[array.Length - 1] = value; } } //0.8秒