A faster loop approach ('for' and 'foreach')?
这个问题源于我在
一些示例代码:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
哪种方式会更便宜?
你总能对它们进行基准测试使用
我认为你会发现,两者几乎相同,因为JIT编译器将数组上的
flevine100实际上是正确的,对于
对于数组来说情况更是如此,因为它们是固定大小的,因此通过JIT编译器进行优化非常简单。
我不会专注于这种微优化水平。
您可能有更好的优化机会,特别是如果您正在处理字符串。 for / foreach差异将是整个运行时的一小部分,它将执行基本相同的操作。
最好使算法尽可能"干净",并在需要时寻找其他性能机会,例如线程化整个例程。
我发现for(...)比foreach()更快。我认为这是因为foreach()使用IEnumerable管道。
因为你关心速度...在.NET 4.0中如果你的循环体不依赖于共享状态,你应该使用Parallel.For或Parallel.Foreach来扩展你的处理到多个处理器。
在第二个示例中,您没有早期退出子句,但添加
我不清楚内部,除了foreach使用枚举器,for循环将取决于元素访问器的可伸缩性。在列表中,一旦添加该中断,它们实际上是相等的。
如果没有基准测试,如果两者之间存在显着差异,我会感到非常惊讶(答案当然,高度依赖于循环内的工作和集合的类型)。
根据我的经验,这些东西从未在生产代码中产生性能瓶颈。任何具有重要意义的应用程序无疑都涉及某种I / O或网络交互,这些交互占据了大部分性能损失。
如果你担心,我强烈建议分析有问题的代码并找出哪个更快。
对于简单的裸阵列,for循环将倾向于产生略小的IL。相比
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); } } |
从VS 2010产生以下IL集,默认发布配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | .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 } |
..但那里的关键部分,循环,基本相同。正如其他人所说,这也是一种微观优化。来自这两种方法的JIT的x86可能会是相同的,除非你使用复杂的枚举器迭代复杂的集合,否则即使在实际的例子中,差异也不大。
我会使用更具可读性的那个 - 如果速度确实非常重要,那么支持for循环,但是你可能会从算法优化中获得更好的结果。