Massimo Guerrera
Massimo Guerrera

Reputation: 53

Slow While loop in C#

I have a while loop and all it does is a method call. I have a timer on the outside of the loop and another timer that incrementally adds up the time the method call takes inside the loop. The outer time takes about 17 seconds and the total on the inner timer is 40 ms. The loop is executing 50,000 times. Here is an example of the code:

long InnerTime = 0;
long OutterTime = 0;
Stopw1.Start();
int count = 1;
while (count <= TestCollection.Count) {
    Stopw2.Start();
    Medthod1();
    Stopw2.Stop();
    InnerTime = InnerTime + Stopw2.ElapsedMilliseconds;
    Stopw2.Reset();
    count++;
}
Stopw1.Stop();
OutterTime = Stopw1.ElapsedMilliseconds;
Stopw1.Reset();

Any help would be much appreciated. Massimo

Upvotes: 5

Views: 2982

Answers (6)

Feng Yuan
Feng Yuan

Reputation: 707

You should not measure such a tiny method individually. But if you really want to, try this:

long innertime = 0;

while (count <= TestCollection.Count) 
{     
    innertime -= Stopw2.GetTimestamp();
    Medthod1();
    innertime += Stopw2.GetTimestamp();
    count++; 
} 

Console.WriteLine("{0} ms", innertime * 1000.0 / Stopw2.Frequency);

Upvotes: 0

Jeffrey Sax
Jeffrey Sax

Reputation: 10323

You are comparing apples and oranges. Your outer timer measures the total time taken. Your inner timer measures the number of whole milliseconds taken by the call to Method1.

The ElapsedMilliseconds property "represents elapsed time rounded down to the nearest whole millisecond value." So, you are rounding down to the nearest millisecond about 50,000 times.

If your call to Method1 takes, on average, less than 1ms, then most of the time, the `ElapsedMilliseconds' property will return 0 and your inner count will be much, much less than the actual time. In fact, your method takes about 0.3ms on average, so you're lucky even to get it to go over 1ms 40 times.

Use the Elapsed.TotalMilliseconds or ElapsedTicks property instead of ElapsedMilliseconds. One millisecond is equivalent to 10,000 ticks.

Upvotes: 8

Mare Infinitus
Mare Infinitus

Reputation: 8182

To have a correct measurement of the time that your calls take, you should use the Ticks

Please try the following:

long InnerTime = 0;
long OutterTime = 0;

Stopwatch Stopw1 = new Stopwatch();
Stopwatch Stopw2 = new Stopwatch();

Stopw1.Start();
int count = 1;
int run = TestCollection.Count;
while (count <= run) {
    Stopw2.Start();
    Medthod1();
    Stopw2.Stop();
    InnerTime = InnerTime + Stopw2.ElapsedTicks;
    Stopw2.Reset();
    count++;
}
Stopw1.Stop();
OutterTime = Stopw1.ElapsedTicks;
Stopw1.Reset();

Upvotes: 0

Eric J.
Eric J.

Reputation: 150118

To add to what the others have already said, in general the C# compiler must re-evaluate any property, including

TestCollection.Count

for every single loop iteration. The property's value could change from iteration to iteration.

Assigning the value to a local variable removes the compiler's need to re-evaluate for every loop iteration.

The one exception that I'm aware of is for Array.Length, which benefits from an optimization specifically for arrays. This is referred to as Array Bounds Check Elimination.

Upvotes: 1

Alex Mendez
Alex Mendez

Reputation: 5150

Try changing this:

while (count <= TestCollection.Count) {
...
}

to this:

int total = TestCollection.Count;
while (count <= total) {
...
}

Upvotes: 1

Chris Dickson
Chris Dickson

Reputation: 12135

What is this doing: TestCollection.Count ?

I suspect your 17 seconds are being spent counting your 50,000 items over and over again.

Upvotes: 2

Related Questions