對《LINQ能不能用系列1數(shù)組篩選效率對比》的幾個問題
引用原文:LINQ能不能用系列(一)數(shù)組篩選效率對比
錯誤一:作為對比測試,測試數(shù)組應該為同一個,否則測試數(shù)據(jù)沒有可比性
錯誤二:對比組中對List的使用不對,List默認創(chuàng)建的數(shù)組大小為4,每次增長為4,那么這里就會反復重新創(chuàng)建新的數(shù)組次數(shù)為log10000000次左右當然會比Linq慢很多
錯誤三:面對Linq接近0毫秒的處理能力,稍微有點經(jīng)驗的同學就知道這是不可能的,除非是很強很強的計算機,至于為什么后面給出答案,總之linq查詢里肯定有貓膩,直接調用tolist()強制返回結果再說;//這里Stone W在評論中對ToList有質疑,我之所以ToList是為了和第二組進行對比,因為第二組得到的結果是一個List,我很奇怪,這次的對比測試到底是為了測試得到兩個結果集的算法對比呢還是測試Count算法的對比呢?如果是前者,一個拿到的是IEnumerable的對象一個是List對象,牛跟鬧鐘怎么對比哪個跑的快呢?也只有在調用ToList的時候才會真正執(zhí)行Linq的算法也就是下面的嵌套類WhereListIterator;當然如果是為了進行Count對比的話那么對比組二中的算法真的有點拙劣,我想不會有誰會用方法二來統(tǒng)計。
下面是修改了如上三個明顯錯誤后的代碼,如果哪位同學有補充歡迎留言:
- [Fact]
- public void LinqTest()
- {
- TestLinq(1);
- TestLinq(2);
- TestLinq(3);
- }
- public void TestLinq(int time)
- {
- const int listCount = 10000000; // 數(shù)組長度
- Random random = new Random(); // 數(shù)據(jù)隨機構建值
- // 數(shù)組構建
- List<int> list1 = new List<int>();
- for (int i = 0; i < listCount; i++)
- {
- list1.Add(random.Next(10000));
- }
- // 效率測試內容:提取數(shù)組中數(shù)值大于的100的數(shù)組
- // LINQ 測試
- Stopwatch linq_Stopwatch = new Stopwatch();
- linq_Stopwatch.Start();
- var linqList = (from num in list1
- where num > 100
- select num).ToList();
- linq_Stopwatch.Stop();
- // 普通方式 測試
- Stopwatch before_Stopwatch = new Stopwatch();
- before_Stopwatch.Start();
- List<int> beforeList = new List<int>(10000000);
- for (int i = 0; i < list1.Count(); i++)
- {
- if (list1[i] > 100)
- beforeList.Add(list1[i]);
- }
- before_Stopwatch.Stop();
- Console.WriteLine(
- String.Format("第{0}次測試,測試:{5}條數(shù)據(jù)。\n\r \t LINQ用時:{1}毫秒,篩選了{2}條數(shù)據(jù)。\n\r\t 普通用時:{3}毫秒,篩選了{4}條數(shù)據(jù)。\r\n",
- time, linq_Stopwatch.ElapsedMilliseconds, linqList.Count(),
- before_Stopwatch.ElapsedMilliseconds, beforeList.Count(), listCount));
- }
測試結果:
第1次測試,測試:10000000條數(shù)據(jù)。
LINQ用時:448毫秒,篩選了9898832條數(shù)據(jù)。
普通用時:437毫秒,篩選了9898832條數(shù)據(jù)。
第2次測試,測試:10000000條數(shù)據(jù)。
LINQ用時:516毫秒,篩選了9899569條數(shù)據(jù)。
普通用時:460毫秒,篩選了9899569條數(shù)據(jù)。
第3次測試,測試:10000000條數(shù)據(jù)。
LINQ用時:608毫秒,篩選了9899231條數(shù)據(jù)。
普通用時:470毫秒,篩選了9899231條數(shù)據(jù)。
結論:LINQ在實現(xiàn)靈活性提高編寫效率的時候犧牲了一定的性能,當然這個是必須的,有的必有失嘛。
我的選擇:絕大部分時候使用Linq,在對性能要求高的時候使用普通的迭代;
0毫秒的秘密:
- var linqList = (from num in list1 where num > 100 select num)
先看看這個LinqList的類型(Console.WriteLine(linqList.GetType().FullName);):System.Linq.Enumerable+WhereListIterator`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
可以看到這是一個嵌套類,作用是對Where 條件進行迭代操作,貼上它的源代碼:
- ?class WhereListIterator<TSource> : Iterator<TSource> {
- List<TSource> source;
- Func<TSource, bool> predicate; List<TSource>.Enumerator enumerator;
- public WhereListIterator(List<TSource> source, Func<TSource, bool> predicate) {
- this.source = source;
- this.predicate = predicate;
- }
- public override Iterator<TSource> Clone() { return new WhereListIterator<TSource>(source, predicate);
- }
- public override bool MoveNext() { switch (state) { case 1: enumerator = source.GetEnumerator(); state = 2;
- goto case 2;
- case 2:
- while (enumerator.MoveNext()) {
- TSource item = enumerator.Current;
- if (predicate(item)) { current = item;
- return true;
- }
- }
- Dispose();
- break; }
- return false; }
- public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) {
- return new WhereSelectListIterator<TSource, TResult>(source, predicate, selector); }
- public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) {
- return new WhereListIterator<TSource>(source, CombinePredicates(this.predicate, predicate));
- } }
真相大白于天下。
ps:下面是原文代碼的截圖
原文鏈接:http://www.cnblogs.com/jinzhao/archive/2012/05/08/2490543.html
【編輯推薦】
- Linq to xml操作XML
- XML之父解讀未來互聯(lián)網(wǎng)"游戲化"的三個真諦
- Ajax和Web服務數(shù)據(jù)格式:XML SOAP HTML
- 超強解析XML——簡單直接的來
- 解析PHP中的XML數(shù)據(jù)