Reputation: 15004
I have run some tests for .Net CF. Basically, I wanted to compare for, foreach, extenstion method ForEach and LINQ query. Here is the whole code (you can skip it, to get to the point which bothers me)
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);
}
}
}
And here I am confused
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();
The ouput is:
For loop test List = 93
List field = 119 // ref -> field
List property = 136 // ref -> property -> field properties are just functions for CF
ForEach test List = 88
List field = 140
List property = 152
Extenstions test List = 176
// another function is called.
List field = 220
List property = 239
LINQ test List = 0 Why?
List field = 163
List property = 165
Why intListTime == 0? What am I doing wrong? Also the last two values for field and property are almost the same (run it a few times). Does it mean that PropertyX in LINQ query is evaluated in-line?
Upvotes: 1
Views: 762
Reputation: 49215
The first time is zero because expression tree is built at compile time and it gets evaluated on ToList
call that you have not included in timing.
For field and property access timing, I wouldn't worry too much - in reality, in release build, simple property accessor will be get inlined giving same performance as field access. For linq case, you might be seeing the same performance because linq internally might be converting property/field access into a method call and it would result in same timings (as I believe that method call overhead will be probably large compared to the field/prop access.
Upvotes: 3
Reputation: 29083
this is called "deferred execution". the linq statement isn't evaluated until it needs to be. move the ToList to be before you stop the clock and the time will go up
Upvotes: 2