开发者

A faster loop approach ('for' and 'foreach')? [duplicate]

This question already has answers here: In .NET, which loop runs faster, 'for' or 'foreach'? (41 answers) Closed 9 years ago.

This question derives from the reason I asked my last question on foreach loops. I have a large string array (say in the thousands), and I want to iterate through the array and also be able to break out based on a certain condition, and I need optimal performance.

Some example code:

for(int i = 0; i < array.length && flag == true; i++){
    //Processing and set flag
}

//..or

foreach(string item in array){
    //processing...set flag
    if(!flag)
        break;开发者_如何学Python
}

Which way would be less expensive?


You can always benchmark them. Use a Stopwatch and iterate over, say, ten million iterations to see which goes faster.

What I think you'll find, though, is that the two are nearly identical since the JIT compiler optimizes foreach on an array to basically a for.

flevine100 is actually right that in general a for is slightly more efficient than a foreach for types whose GetEnumerator methods create a new object implementing IEnumerator or IEnumerator<T> (due to the memory allocation and method call overhead); this is less the case for most of the collections in System.Collections.Generic, however, due to their explicit IEnumerable implementation using value type enumerators (not to mention that the foreach construct does not actually require an IEnumerable implementation in the first place).

It's even less the case for arrays specifically because they are fixed-size and therefore trivial to optimize by the JIT compiler.


I have found that for(...) is faster than foreach(). I think it's because foreach() uses the IEnumerable plumbing.

Since you're concerned about speed... In .NET 4.0 If your loop body is not relying on shared state, you should use Parallel.For or Parallel.Foreach to scale your processing out onto multiple processors.


I would not focus on this level of micro-optimization.

Chances are you have much better optimization opportunities, especially if you're working on strings. for/foreach differences will be such a small fraction of your overall runtime that it will perform essentially the same.

It would be much better to make the algorithm as "clean" as possible, and look for other performance opportunities if required, such as threading the entire routine.


In the second example you don't have an early exit clause, though adding break in place of your flag will achieve that.

I'm unclear of internals except that foreach uses Enumerators and the for loop will depend on the scalability of your element accessor. On a list they are effectively equal once you add that break.


Without benchmarking, I would be very surprised if there was a noticeable difference between the two (the answer, of course, is highly dependent on the work being done within the loop and the type of collection).

These are the kinds of things that, in my experience, never create performance bottlenecks in production code. Any application that does anything significant is undoubtedly involved with some sort of I/O or network interaction that accounts for the the majority of the performance penalty.

If you are concerned though, I would highly recommend profiling the offending code and find which is faster.


For a simple bare array, the for loop will tend to produce slightly smaller IL. Compare

    static int[] array = new int[100];

    static void UseForLoop () {
        for (int i = 0; i < array.Length; ++i) {
            Console.WriteLine(array[i]);
        }
    }

    static void UseForeachLoop () {
        foreach (int i in array) {
            Console.WriteLine(i);
        }
    }

which produces the following sets of IL from VS 2010, default release configuration:

.method private hidebysig static void UseForLoop() cil managed
{
        .maxstack 2
        .locals init (
                [0] int32 i)
        L_0000: ldc.i4.0 
        L_0001: stloc.0 
        L_0002: br.s L_0014
        L_0004: ldsfld int32[] ConsoleApplication5.Program::array
        L_0009: ldloc.0 
        L_000a: ldelem.i4 
        L_000b: call void [mscorlib]System.Console::WriteLine(int32)
        L_0010: ldloc.0 
        L_0011: ldc.i4.1 
        L_0012: add 
        L_0013: stloc.0 
        L_0014: ldloc.0 
        L_0015: ldsfld int32[] ConsoleApplication5.Program::array
        L_001a: ldlen 
        L_001b: conv.i4 
        L_001c: blt.s L_0004
        L_001e: ret 
}

.method private hidebysig static void UseForeachLoop() cil managed
{
        .maxstack 2
        .locals init (
                [0] int32 i,
                [1] int32[] CS$6$0000,
                [2] int32 CS$7$0001)
        L_0000: ldsfld int32[] ConsoleApplication5.Program::array
        L_0005: stloc.1 
        L_0006: ldc.i4.0 
        L_0007: stloc.2 
        L_0008: br.s L_0018
        L_000a: ldloc.1 
        L_000b: ldloc.2 
        L_000c: ldelem.i4 
        L_000d: stloc.0 
        L_000e: ldloc.0 
        L_000f: call void [mscorlib]System.Console::WriteLine(int32)
        L_0014: ldloc.2 
        L_0015: ldc.i4.1 
        L_0016: add 
        L_0017: stloc.2 
        L_0018: ldloc.2 
        L_0019: ldloc.1 
        L_001a: ldlen 
        L_001b: conv.i4 
        L_001c: blt.s L_000a
        L_001e: ret 
}

..but the key parts there, the loops, are basically the same. As others have said, this is kind of a micro-optimization, too. The JIT'd x86 from these two methods is probably going to be the same, and unless your iterating over a complex collection with a complicated enumerator, the difference is not likely to be huge even in a practical example.

I'd use the one that is more readable -- if speed is really that much of a concern, favor a for loop, but you'd likely get better results from algorithmic optimizations.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜