對(duì)《LINQ能不能用系列1數(shù)組篩選效率對(duì)比》的幾個(gè)問題
引用原文:LINQ能不能用系列(一)數(shù)組篩選效率對(duì)比
錯(cuò)誤一:作為對(duì)比測(cè)試,測(cè)試數(shù)組應(yīng)該為同一個(gè),否則測(cè)試數(shù)據(jù)沒有可比性
錯(cuò)誤二:對(duì)比組中對(duì)List的使用不對(duì),List默認(rèn)創(chuàng)建的數(shù)組大小為4,每次增長為4,那么這里就會(huì)反復(fù)重新創(chuàng)建新的數(shù)組次數(shù)為log10000000次左右當(dāng)然會(huì)比Linq慢很多
錯(cuò)誤三:面對(duì)Linq接近0毫秒的處理能力,稍微有點(diǎn)經(jīng)驗(yàn)的同學(xué)就知道這是不可能的,除非是很強(qiáng)很強(qiáng)的計(jì)算機(jī),至于為什么后面給出答案,總之linq查詢里肯定有貓膩,直接調(diào)用tolist()強(qiáng)制返回結(jié)果再說;//這里Stone W在評(píng)論中對(duì)ToList有質(zhì)疑,我之所以ToList是為了和第二組進(jìn)行對(duì)比,因?yàn)榈诙M得到的結(jié)果是一個(gè)List,我很奇怪,這次的對(duì)比測(cè)試到底是為了測(cè)試得到兩個(gè)結(jié)果集的算法對(duì)比呢還是測(cè)試Count算法的對(duì)比呢?如果是前者,一個(gè)拿到的是IEnumerable的對(duì)象一個(gè)是List對(duì)象,牛跟鬧鐘怎么對(duì)比哪個(gè)跑的快呢?也只有在調(diào)用ToList的時(shí)候才會(huì)真正執(zhí)行Linq的算法也就是下面的嵌套類WhereListIterator;當(dāng)然如果是為了進(jìn)行Count對(duì)比的話那么對(duì)比組二中的算法真的有點(diǎn)拙劣,我想不會(huì)有誰會(huì)用方法二來統(tǒng)計(jì)。
下面是修改了如上三個(gè)明顯錯(cuò)誤后的代碼,如果哪位同學(xué)有補(bǔ)充歡迎留言:
- [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ù)隨機(jī)構(gòu)建值
- // 數(shù)組構(gòu)建
- List<int> list1 = new List<int>();
- for (int i = 0; i < listCount; i++)
- {
- list1.Add(random.Next(10000));
- }
- // 效率測(cè)試內(nèi)容:提取數(shù)組中數(shù)值大于的100的數(shù)組
- // LINQ 測(cè)試
- Stopwatch linq_Stopwatch = new Stopwatch();
- linq_Stopwatch.Start();
- var linqList = (from num in list1
- where num > 100
- select num).ToList();
- linq_Stopwatch.Stop();
- // 普通方式 測(cè)試
- 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}次測(cè)試,測(cè)試:{5}條數(shù)據(jù)。\n\r \t LINQ用時(shí):{1}毫秒,篩選了{(lán)2}條數(shù)據(jù)。\n\r\t 普通用時(shí):{3}毫秒,篩選了{(lán)4}條數(shù)據(jù)。\r\n",
- time, linq_Stopwatch.ElapsedMilliseconds, linqList.Count(),
- before_Stopwatch.ElapsedMilliseconds, beforeList.Count(), listCount));
- }
測(cè)試結(jié)果:
第1次測(cè)試,測(cè)試:10000000條數(shù)據(jù)。
LINQ用時(shí):448毫秒,篩選了9898832條數(shù)據(jù)。
普通用時(shí):437毫秒,篩選了9898832條數(shù)據(jù)。
第2次測(cè)試,測(cè)試:10000000條數(shù)據(jù)。
LINQ用時(shí):516毫秒,篩選了9899569條數(shù)據(jù)。
普通用時(shí):460毫秒,篩選了9899569條數(shù)據(jù)。
第3次測(cè)試,測(cè)試:10000000條數(shù)據(jù)。
LINQ用時(shí):608毫秒,篩選了9899231條數(shù)據(jù)。
普通用時(shí):470毫秒,篩選了9899231條數(shù)據(jù)。
結(jié)論:LINQ在實(shí)現(xiàn)靈活性提高編寫效率的時(shí)候犧牲了一定的性能,當(dāng)然這個(gè)是必須的,有的必有失嘛。
我的選擇:絕大部分時(shí)候使用Linq,在對(duì)性能要求高的時(shí)候使用普通的迭代;
0毫秒的秘密:
- var linqList = (from num in list1 where num > 100 select num)
先看看這個(gè)LinqList的類型(Console.WriteLine(linqList.GetType().FullName);):System.Linq.Enumerable+WhereListIterator`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
可以看到這是一個(gè)嵌套類,作用是對(duì)Where 條件進(jìn)行迭代操作,貼上它的源代碼:
- ?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)"游戲化"的三個(gè)真諦
- Ajax和Web服務(wù)數(shù)據(jù)格式:XML SOAP HTML
- 超強(qiáng)解析XML——簡(jiǎn)單直接的來
- 解析PHP中的XML數(shù)據(jù)