473,598 Members | 2,916 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

C# compiler fails to optimize for loop same as foreach

I came across a reference on a web site
(http://www.personalmicrocosms.com/ht...htextbox_lines )
that said to speed up access to a rich text box's lines that you needed to
use a "foreach" loop instead of a "for" loop. This made absolutely no sense
to me, but the author had posted his code and timing results. The "foreach"
(a VB and other languages construct) was 0.01 seconds to access 1000 lines in
rich text box, whereas the "for" loop (a traditional C++ construct) was an
astounding 25 seconds (on a not very fast PC).

I recreated a test file using the partial source code posted by the author
and verified that there is a SIGNIFICANT performance difference between the
two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds - still
a noticeable delay). Unfortunately, there was no explanation as to why this
was the case and I couldn't see anything as to why one loop construct would
be different. Looking at the generated IL code with Lutz Roeder's Reflector
tool, I see that the real culprit is not the loop structure but the
get_Lines() function that is pulled out of the loop in the "foreach" loop and
not in the "for" loop code. Which, leads to me post this question about the
differences in complier code generation/optimization and is there any setting
that can change this.

Interestingly, this is true for both Debug and Release builds. The compiler
generated code that called that function twice for each pass of the loop
(once for the loop index check and then again for the length calculation).
Pulling out unneccessary function calls is pretty basic optimization, and I
surprised that the compiler didn't detect this.

With the IDE's intellisense and auto completion features, the "for" loop
construct shown in the code below seems like something that someone might
actually code up, and of course who would have figured out that the get_Lines
method would be so performance intensive.

Makes me wonder if there are any other gotchas like this.

Thanks, Mike L.

--------------------------------------------------------------------------------------------

//Simple windows form with a richtextbox control, initialized w/1000 lines
of text (e.g., "line #101", etc).

private void ForLoopButton_C lick(object sender, System.EventArg s e)
{
Cursor.Current = Cursors.WaitCur sor;
int Len = 0;
int Start = Environment.Tic kCount;
for (int i = 0; i < TheRichTextBox. Lines.Length; i++)
{
Len += TheRichTextBox. Lines[i].Length;
}
int ElapsedTime = Environment.Tic kCount - Start;
ResultsTextBox. Clear();
RsultsTextBox.T ext = "for loop\r\n\r\nEla psed time = " + ((double)
ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForEachLoopButt on_Click(object sender, System.EventArg s e)
{
Cursor.Current = Cursors.WaitCur sor;
int Len = 0;
int Start = Environment.Tic kCount;
foreach (String Line in TheRichTextBox. Lines)
{
Len += Line.Length;
}
int ElapsedTime = Environment.Tic kCount - Start;
ResultsTextBox. Clear();
ResultsTextBox. Text = "foreach loop\r\n\r\nEla psed time = " + ((double)
ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForLoopButton2_ Click(object sender, System.EventArg s e)
{
//Performance results now same as ForEachLoopButt on_Click with the changes
made.
Cursor.Current = Cursors.WaitCur sor;
int Len = 0;
int Start = Environment.Tic kCount;
string[] lines = TheTextBox.Line s;
for (int i = 0; i < lines.Length; i++)
{
Len += lines[i].Length;
}
int ElapsedTime = Environment.Tic kCount - Start;
ResultsTextBox. Clear();
RsultsTextBox.T ext = "for loop\r\n\r\nEla psed time = " + ((double)
ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

Nov 16 '05 #1
15 2667

"Mike Lansdaal" <ml*****@newsgr oup.nospam> wrote in message
news:70******** *************** ***********@mic rosoft.com...
I came across a reference on a web site
(http://www.personalmicrocosms.com/ht...htextbox_lines ) that said to speed up access to a rich text box's lines that you needed to
use a "foreach" loop instead of a "for" loop. This made absolutely no sense to me, but the author had posted his code and timing results. The "foreach" (a VB and other languages construct) was 0.01 seconds to access 1000 lines in rich text box, whereas the "for" loop (a traditional C++ construct) was an
astounding 25 seconds (on a not very fast PC).

I recreated a test file using the partial source code posted by the author
and verified that there is a SIGNIFICANT performance difference between the two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds - still a noticeable delay). Unfortunately, there was no explanation as to why this was the case and I couldn't see anything as to why one loop construct would be different. Looking at the generated IL code with Lutz Roeder's Reflector tool, I see that the real culprit is not the loop structure but the
get_Lines() function that is pulled out of the loop in the "foreach" loop and not in the "for" loop code. Which, leads to me post this question about the differences in complier code generation/optimization and is there any setting that can change this.

Interestingly, this is true for both Debug and Release builds. The compiler generated code that called that function twice for each pass of the loop
(once for the loop index check and then again for the length calculation).
Pulling out unneccessary function calls is pretty basic optimization, and I surprised that the compiler didn't detect this.

With the IDE's intellisense and auto completion features, the "for" loop
construct shown in the code below seems like something that someone might
actually code up, and of course who would have figured out that the get_Lines method would be so performance intensive.

Makes me wonder if there are any other gotchas like this.

Thanks, Mike L.

-------------------------------------------------------------------------- ------------------
//Simple windows form with a richtextbox control, initialized w/1000 lines
of text (e.g., "line #101", etc).

private void ForLoopButton_C lick(object sender, System.EventArg s e)
{
Cursor.Current = Cursors.WaitCur sor;
int Len = 0;
int Start = Environment.Tic kCount;
for (int i = 0; i < TheRichTextBox. Lines.Length; i++)
{
Len += TheRichTextBox. Lines[i].Length;
}
int ElapsedTime = Environment.Tic kCount - Start;
ResultsTextBox. Clear();
RsultsTextBox.T ext = "for loop\r\n\r\nEla psed time = " + ((double)
ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForEachLoopButt on_Click(object sender, System.EventArg s e)
{
Cursor.Current = Cursors.WaitCur sor;
int Len = 0;
int Start = Environment.Tic kCount;
foreach (String Line in TheRichTextBox. Lines)
{
Len += Line.Length;
}
int ElapsedTime = Environment.Tic kCount - Start;
ResultsTextBox. Clear();
ResultsTextBox. Text = "foreach loop\r\n\r\nEla psed time = " + ((double)
ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForLoopButton2_ Click(object sender, System.EventArg s e)
{
//Performance results now same as ForEachLoopButt on_Click with the changes
made.
Cursor.Current = Cursors.WaitCur sor;
int Len = 0;
int Start = Environment.Tic kCount;
string[] lines = TheTextBox.Line s;
for (int i = 0; i < lines.Length; i++)
{
Len += lines[i].Length;
}
int ElapsedTime = Environment.Tic kCount - Start;
ResultsTextBox. Clear();
RsultsTextBox.T ext = "for loop\r\n\r\nEla psed time = " + ((double)
ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}


Amazing! I had no idea. I sure hope someone is capable of explaining this.

/ Fredrik
Nov 16 '05 #2

Hi

I found something here that may explain this problem:
http://www.codeproject.com/csharp/foreach.asp

/ Fredrik
Nov 16 '05 #3

"Mike Lansdaal" <ml*****@newsgr oup.nospam> wrote in message
news:70******** *************** ***********@mic rosoft.com...
I came across a reference on a web site
(http://www.personalmicrocosms.com/ht...htextbox_lines
)
that said to speed up access to a rich text box's lines that you needed to
use a "foreach" loop instead of a "for" loop. This made absolutely no
sense
to me, but the author had posted his code and timing results. The
"foreach"
(a VB and other languages construct) was 0.01 seconds to access 1000 lines
in
rich text box, whereas the "for" loop (a traditional C++ construct) was an
astounding 25 seconds (on a not very fast PC).

I recreated a test file using the partial source code posted by the author
and verified that there is a SIGNIFICANT performance difference between
the
two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds -
still
a noticeable delay). Unfortunately, there was no explanation as to why
this
was the case and I couldn't see anything as to why one loop construct
would
be different. Looking at the generated IL code with Lutz Roeder's
Reflector
tool, I see that the real culprit is not the loop structure but the
get_Lines() function that is pulled out of the loop in the "foreach" loop
and
not in the "for" loop code. Which, leads to me post this question about
the
differences in complier code generation/optimization and is there any
setting
that can change this.


Ah. It's not a compiler problem. It's a property problem.

get_Lines() is expensive. Who Knew? That's the problem with properties: you
never know how much code they run.

Anyway, try this:

string[] lines = TheRichTextBox. Lines;
for (int i = 0; i < lines.Length; i++)
{
Len += lines[i].Length;
}

It should be similar to the foreach case.

David
Nov 16 '05 #4
Frederik - Interesting article (which recommends to always use for instead of
foreach, but also generated opposing thoughts). I found this blog link in
the article comments
(http://blogs.msdn.com/brada/archive/...29/123105.aspx ) which suggests
that the code generation forthe two loop types are "bascially identical" and
that a "foreach" is recommended for "clarity".

Thanks, Mike

"Fredrik Wahlgren" wrote:

Hi

I found something here that may explain this problem:
http://www.codeproject.com/csharp/foreach.asp

/ Fredrik

Nov 16 '05 #5
Yes, exactly. Thats what I did (and that's what the foreach does). My
concern was that in one case the compiler did one thing (pulled the property
call out of the loop) and in another case didn't (in the for loop case, its
there for the loop check and again for the calcuation).

Thanks, Mike

"David Browne" wrote:

"Mike Lansdaal" <ml*****@newsgr oup.nospam> wrote in message
news:70******** *************** ***********@mic rosoft.com...
I came across a reference on a web site
(http://www.personalmicrocosms.com/ht...htextbox_lines
)
that said to speed up access to a rich text box's lines that you needed to
use a "foreach" loop instead of a "for" loop. This made absolutely no
sense
to me, but the author had posted his code and timing results. The
"foreach"
(a VB and other languages construct) was 0.01 seconds to access 1000 lines
in
rich text box, whereas the "for" loop (a traditional C++ construct) was an
astounding 25 seconds (on a not very fast PC).

I recreated a test file using the partial source code posted by the author
and verified that there is a SIGNIFICANT performance difference between
the
two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds -
still
a noticeable delay). Unfortunately, there was no explanation as to why
this
was the case and I couldn't see anything as to why one loop construct
would
be different. Looking at the generated IL code with Lutz Roeder's
Reflector
tool, I see that the real culprit is not the loop structure but the
get_Lines() function that is pulled out of the loop in the "foreach" loop
and
not in the "for" loop code. Which, leads to me post this question about
the
differences in complier code generation/optimization and is there any
setting
that can change this.


Ah. It's not a compiler problem. It's a property problem.

get_Lines() is expensive. Who Knew? That's the problem with properties: you
never know how much code they run.

Anyway, try this:

string[] lines = TheRichTextBox. Lines;
for (int i = 0; i < lines.Length; i++)
{
Len += lines[i].Length;
}

It should be similar to the foreach case.

David

Nov 16 '05 #6

"Mike Lansdaal" <ml*****@newsgr oup.nospam> wrote in message
news:3E******** *************** ***********@mic rosoft.com...
Yes, exactly. Thats what I did (and that's what the foreach does). My
concern was that in one case the compiler did one thing (pulled the
property
call out of the loop) and in another case didn't (in the for loop case,
its
there for the loop check and again for the calcuation).


Well in the for loop it can't pull it out. For all the compiler knows
get_Lines() might start returning a completely different array half way
through the iteration.

In the foreach case, the compiler has more information. It knows that it's
iterating the result of get_Lines().
David
Nov 16 '05 #7
David - Thanks. I think I was assuming something about the context of the
iteration, but I see that with your explanation that it would be impossible
for the compiler to determine that.

Thanks, Mike

"David Browne" wrote:

"Mike Lansdaal" <ml*****@newsgr oup.nospam> wrote in message
news:3E******** *************** ***********@mic rosoft.com...
Yes, exactly. Thats what I did (and that's what the foreach does). My
concern was that in one case the compiler did one thing (pulled the
property
call out of the loop) and in another case didn't (in the for loop case,
its
there for the loop check and again for the calcuation).


Well in the for loop it can't pull it out. For all the compiler knows
get_Lines() might start returning a completely different array half way
through the iteration.

In the foreach case, the compiler has more information. It knows that it's
iterating the result of get_Lines().
David

Nov 16 '05 #8
Hi Mike,

Here is an official document from MSDN. I think it will be clearer after
checking this article.

http://msdn.microsoft.com/library/de...us/dnpag/html/
scalenetchapt05 .asp

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 16 '05 #9
Hi Mike,

Generally, a For loop has better performance than Foreach loop. In the link
you have provided in your first post, there are some differences between
For and Foreach loop which make the performance much differenct. For
example,

for (int i = 0; i < TheRichTextBox. Lines.Length; i++)

Since RichTextBox.Len gth returns length by caculating, so each time in the
loop, this property will be called. Also this calculating the length takes
a lot of time, since it needs to go through all the text in the
RichTextbox. If you change the code to the following, the return time will
tremendously decrease.

int a=TheRichTextBo x.Lines.Length;
for (int i = 0; i < a; i++)

There are also many other differences in getting the line reference here.
So I don't think this tesing result is reliable. Please refer to the
official document as I provided in my last post.

HTH.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 16 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
3122
by: joshc | last post by:
I'm writing some C to be used in an embedded environment and the code needs to be optimized. I have a question about optimizing compilers in general. I'm using GCC for the workstation and Diab compiler for the embedded target. My question is about how compilers optimize certain code sequences. As an example, take the code below. Will the compiler eliminate the actual function call to foo() in the object code generated and just store...
11
1291
by: Flinchvoid | last post by:
Interesting little problem; go easy on me because I'm just a humble scripter turned c# developer. I've a class UserList which I auto-generated with a python script, it extends CollectionBase and has the usual methods: this, Add, Insert, Remove and Contains. There are no differences between this class and the other generated classes I'm using other than the type of the contained object. The other classes can be foreach'ed quite happily.
13
14456
by: TrintCSD | last post by:
How can I reset the collections within a foreach to be read as a change from within the foreach loop then restart the foreach after collections has been changed? foreach(string invoice in findListBox.listBox2.Items) { listBox2.Items count changed, restart this foreach } Thanks for any help.
3
1352
by: babak | last post by:
Hi I am running a project in eVC 4.0 and I have been running into a bug that only appears in the release build of the project. I eventually found out that when I had the compiler option /Od set the project would work properly but when it was not set the bug would appear. I looked for /Od in the MSDN library but it didn't provide much help. Can anyone help me with what in my code that could lead to this? I.e what should I look for in my...
44
3210
by: Don Kim | last post by:
Ok, so I posted a rant earlier about the lack of marketing for C++/CLI, and it forked over into another rant about which was the faster compiler. Some said C# was just as fast as C++/CLI, whereas others said C++/CLI was more optimized. Anyway, I wrote up some very simple test code, and at least on my computer C++/CLI came out the fastest. Here's the sample code, and just for good measure I wrote one in java, and it was the slowest! ;-)...
6
1280
by: Steeve | last post by:
Hi, Is this possible to optimize this method ? It's the method than I call most offen in my application (result of Sampling Profiling in Visual Studio Performance report) I use this method to find a particular Node in a List<Node>. (Note: JobNumber is a int) public bool NodeMachineJobPredicate(Node N)
3
33348
by: Akira | last post by:
I noticed that using foreach is much slower than using for-loop, so I want to change our current code from foreach to for-loop. But I can't figure out how. Could someone help me please? Current code is here: foreach ( string propertyName in ht.Keys ) { this.setProperty( propertyName, ht );
49
2107
by: valentin tihomirov | last post by:
fDeleted = false; uint jobId; foreach (Struct struct in structures) { if (struct.type == JOB) { jobId = struct.id; if (struct.dataType == STATUS) fDeteted = (struct.data & STATUS_DELETED) != 0; }
5
2521
by: timor.super | last post by:
Hi group, imagine I want to find number of values of a word in a string ... Look at my code : List<stringthingsToFind = new List<string>(new string {"error", "values"}); MyClass myClass = new MyClass(thingsToFind, data); foreach (KeyValuePair<int, stringaValue in
0
7981
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8284
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8392
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8046
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8262
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
5847
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5437
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
1500
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
1245
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.