Point take, I added comments to the entry and a *work-around* to root the value
bar so it can't be optimized away by the JIT, assuming the JIT would ever do
such
a thing.
Someone asserted that the JIT might optimize out the entire loop and make it
*not happen* because the resulting value isn't being used. I think this is a
highly unfounded assertion, but just in case, you'd think we might be able to
save the JIT the trouble of optimizing things out by appending the bar variable
onto the Console.WriteLine call. Once you do that, the variable bar becomes
*used* and so the JIT couldn't possibly optimize it out.
However, I know the JIT wasn't optimizing things out because I was viewing the
resulting assembler for each of the above methods and watching it run. I think
that asking the JIT to optimize all of the above code out would be a rather tall
order, but I'm assuming the metrics could be there for it. As a human compiler I
would optimize the code out since I would realize the value of bar was never
used and so the iteration was for naught.
I guess the days of using looping constructs to count time away are over. No
more: "Please insert an integer between 1 and 10000: " when you start running a
game under the GW BASIC interpreter. And I thought I was so slick when I wrote
my own custom timing function to get rid of that message for good, so no user
ever had to feel the wrath of submarines and torpedos at warp speed on their
ultra fast new 386.
<<< END Comment
--
Justin Rogers
DigiTec Web Consultants, LLC.
Blog:
http://weblogs.asp.net/justin_rogers
Bill McCarthy said:
Hi Justin,
Justin Rogers said:
Are those tests you did actually doing anything though ? They don't appear
to be either reading to or writing from the array. Obviously, if you are
comparing foreach with for, then due to the limitations of foreach, you
can't actually be writing to the array. So a realistic test would be reading
from the elements.
All of the tests are using the array element to update a local variable. Hence
the bar+=foo
, or in the case of foreach bar+=i;
But it is still doing nothing. The local variable is not passed out of the
method, and because it is a local variable that is not used anywhere else
other than the assignment to it, an optimising JIT compiler can actually
decide to skip that code. When you do bench tests and report anomolties,
it's probalby best to avoid such code that can be optimised out, if it is
that code you are actually trying to test
The point was that foreach doesn't even create an enumerator when iterating
an array.
Right, for arrays only. For anything else that implements IList, this is
not the case. That's why I referred to thread safe enumerators, which you
probably know an array's enumerator is not.
That is made quite obvious by my examination of the IL locals for
both the for instance, and the foreach instance.
Uhm jsut a suggestion, it would have been made clearer if you actually
included the IL you were referring to
Not to be harsh, but it looks like you probably didn't read the blog entry. I
note that there is no enumerator when using foreach. There are instead
optimizations made by the C# compiler. I talk about all of these optimizations
in the article, so I won't enumerate them again here. The main optimization,
however, is that foreach DOES NOT create an enumerator when iterating
over an array of integers.
Not with you there. Seems we are perhaps talking past each other. Arrays do
not have thread safe enumeration.