Linq表现和延迟执行

时间:2011-01-21 03:57:49

标签: c# linq windows-phone-7

我为.Net CF运行了一些测试。基本上,我想比较,foreach,扩展方法ForEach和LINQ查询。这是整个代码(你可以跳过它,以达到困扰我的地步)

namespace ForEachForLINQPerTest
{
 class IntBox
 {
    public int fieldX;
    public int PropertyX { get; set; }
 }

 public partial class MainPage : PhoneApplicationPage
 {
    /// <summary>
    /// size of tested List
    /// </summary>
    public const int TEST_SIZE = 1000000;

    //
    private List<int> m_intList = new List<int>(TEST_SIZE);

    //
    private List<IntBox> m_intBoxList = new List<IntBox>(TEST_SIZE);

    //
    private Stopwatch m_stopwatch = null;
    // Constructor
    public MainPage()
    {
        InitializeComponent();

        for (int i = 0; i < TEST_SIZE; ++i)
        {
            m_intBoxList.Add( new IntBox());
            m_intList.Add(0);
        }
    }

    private void startButton_Click(object sender, RoutedEventArgs e)
    {
        var forTest = ForTest(); // Jitter preheat
        forTest = ForTest();
        forResultTextBlock.Text = forTest;

        var foreachTest = ForEachTest();
        foreachTest = ForEachTest();
        foreachResultTextBlock.Text = foreachTest;

        var exTest = Extenstion();
        exTest = Extenstion();
        ExtensionResultTextBlock.Text = exTest;

        var linqTest = LINQTest();
        linqTest = LINQTest();
        LINQResultTextBlock.Text = linqTest;
    }

    private string LINQTest()
    {
        m_stopwatch = new Stopwatch();
        m_stopwatch.Start();
        long temp = 0;
        var result = from x in m_intList
                     select temp += x;            
        m_stopwatch.Stop();
        var intListTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();
        result.ToList();


        m_stopwatch.Start();
        var result2 = from x in m_intBoxList
                     select temp += x.fieldX;    
        m_stopwatch.Stop();
        var intBoxListFieldTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();
        result2.ToList();

        m_stopwatch.Start();
        var result3 = from x in m_intBoxList
                      select temp += x.PropertyX;    
        m_stopwatch.Stop();
        var intBoxListPropertyTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();
        result3.ToList();
        return String.Format("LINQ test List<int> = {0} \n List<IntBox> field = {1} \n List<IntBos> property = {2}", intListTime, intBoxListFieldTime, intBoxListPropertyTime); 
    }

    private string Extenstion()
    {
        m_stopwatch = new Stopwatch();
        m_stopwatch.Start();
        long temp = 0;
        m_intList.ForEach(i => temp += i);
        m_stopwatch.Stop();
        var intListTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();


        m_stopwatch.Start();
        m_intBoxList.ForEach(i => temp += i.fieldX);
        m_stopwatch.Stop();
        var intBoxListFieldTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();

        m_stopwatch.Start();
        m_intBoxList.ForEach(i => temp += i.PropertyX);
        m_stopwatch.Stop();
        var intBoxListPropertyTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();
        return String.Format("Extenstion test List<int> = {0} \n List<IntBox> field = {1} \n List<IntBos> property = {2}", intListTime, intBoxListFieldTime, intBoxListPropertyTime); 
    }

    private string ForEachTest()
    {
        m_stopwatch = new Stopwatch();
        long temp = 0;
        m_stopwatch.Start();
        foreach(int item in m_intList)
        {
           temp += item;
        }
        m_stopwatch.Stop();
        var intListTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();


        m_stopwatch.Start();
        foreach (IntBox item in m_intBoxList)
        {
            temp += item.fieldX;
        }
        m_stopwatch.Stop();
        var intBoxListFieldTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();

        m_stopwatch.Start();
        foreach (IntBox item in m_intBoxList)
        {
            temp += item.PropertyX;
        }
        m_stopwatch.Stop();
        var intBoxListPropertyTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();

        return String.Format("ForEach test List<int> = {0} \n List<IntBox> field = {1} \n List<IntBos> property = {2}", intListTime, intBoxListFieldTime, intBoxListPropertyTime); 
    }

    private string ForTest()
    {
        m_stopwatch = new Stopwatch();
        m_stopwatch.Start();
        long temp = 0;
        for (int i = 0; i < TEST_SIZE; ++i)
        {
            temp += m_intList[i];
        }
        m_stopwatch.Stop();
        var intListTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();


        m_stopwatch.Start();
        for (int i = 0; i < m_intList.Count; ++i)
        {
            temp += m_intBoxList[i].fieldX;
        }
        m_stopwatch.Stop();
        var intBoxListFieldTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();

        m_stopwatch.Start();
        for (int i = 0; i < m_intList.Count; ++i)
        {
           temp +=  m_intBoxList[i].PropertyX;
        }
        m_stopwatch.Stop();
        var intBoxListPropertyTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();

        return String.Format("For loop test List<int> = {0} \n List<IntBox> field = {1} \n List<IntBos> property = {2}", intListTime, intBoxListFieldTime, intBoxListPropertyTime); 
    }
 }
}

在这里我很困惑

        m_stopwatch = new Stopwatch();
        m_stopwatch.Start();
        long temp = 0;
        var result = from x in m_intList
                     select temp += x;            
        m_stopwatch.Stop();
        var intListTime = m_stopwatch.ElapsedMilliseconds;
        m_stopwatch.Reset();
        result.ToList();

输出是:

对于循环测试列表= 93
列表字段= 119 // ref - &gt;领域
List property = 136 // ref - &gt; property - &gt;字段属性只是CF的功能

ForEach test List = 88
列表字段= 140
清单属性= 152

扩展测试列表= 176
//调用另一个函数。 列表字段= 220
清单属性= 239

LINQ测试列表= 0为什么?
列表字段= 163
清单属性= 165

为什么intListTime == 0?我究竟做错了什么?字段和属性的最后两个值几乎相同(运行几次)。这是否意味着LINQ查询中的PropertyX是在线评估的?

2 个答案:

答案 0 :(得分:3)

第一次为零,因为表达式树是在编译时构建的,并且会在ToList调用中评估您未包含在计时中。

对于字段和属性访问时间,我不会太担心 - 实际上,在发布版本中,简单的属性访问器将被内联,提供与字段访问相同的性能。对于linq情况,您可能会看到相同的性能,因为linq内部可能会将属性/字段访问转换为方法调用,并且会导致相同的时序(因为我相信与字段/ prop相比,方法调用开销可能会很大访问。

答案 1 :(得分:2)

这称为“延期执行”。 linq语句在需要之前不会被评估。在停止时钟之前移动ToList,时间会上升