IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]c# 中的 for vs foreach

    csharp25发表于 2015-12-18 17:47:34
    love 0

    今天偶然与建议不要用for,可读性太差性能又低,可我个人认为要根据具体情况而定,毕竟for在大部分语言的关键字,可读性不可能因为一个关键字的替代而变好,多数取决于设计和编码习惯。
    至于性能,打算写段代码对它们分别测试一下。
    var arr = Enumerable.Range(0, 100000000).ToList();
    	
    	var sw = Stopwatch.StartNew();
    	for(var i = 0;i < arr.Count; i++){}
    	sw.Stop();
    	Console.WriteLine("for loop takes : " + sw.ElapsedTicks);
    	
    	sw = Stopwatch.StartNew();
    	foreach(var x in arr){}
    	sw.Stop();
    	Console.WriteLine("for loop takes : " + sw.ElapsedTicks);




    先看生成的IL


    for循环的部分:
    ...
    IL_0018:  ldc.i4.0    
    IL_0019:  stloc.2     // i
    IL_001A:  br.s        IL_0022
    IL_001C:  nop         
    IL_001D:  nop         
    IL_001E:  ldloc.2     // i
    IL_001F:  ldc.i4.1    
    IL_0020:  add         
    IL_0021:  stloc.2     // i
    IL_0022:  ldloc.2     // i
    IL_0023:  ldloc.0     // arr
    IL_0024:  callvirt    System.Collections.Generic.List<System.Int32>.get_Count
    IL_0029:  clt         
    IL_002B:  stloc.s     04 // CS$4$0000
    IL_002D:  ldloc.s     04 // CS$4$0000
    IL_002F:  brtrue.s    IL_001C
    
    
    ...




    除了IL_0024中的callvirt会触发方法虚表查询外,几乎不存在任何高消耗的指令。再来看foreach的IL部分:


    ...
    IL_005A:  ldloc.0     // arr
    IL_005B:  callvirt    System.Collections.Generic.List<System.Int32>.GetEnumerator
    IL_0060:  stloc.s     05 // CS$5$0001
    IL_0062:  br.s        IL_006E
    IL_0064:  ldloca.s    05 // CS$5$0001
    IL_0066:  call        System.Collections.Generic.List<System.Int32>+Enumerator.get_Current
    IL_006B:  stloc.3     // x
    IL_006C:  nop         
    IL_006D:  nop         
    IL_006E:  ldloca.s    05 // CS$5$0001
    IL_0070:  call        System.Collections.Generic.List<System.Int32>+Enumerator.MoveNext
    IL_0075:  stloc.s     04 // CS$4$0000
    IL_0077:  ldloc.s     04 // CS$4$0000
    IL_0079:  brtrue.s    IL_0064
    IL_007B:  leave.s     IL_008C
    IL_007D:  ldloca.s    05 // CS$5$0001
    IL_007F:  constrained. System.Collections.Generic.List<>.Enumerator
    IL_0085:  callvirt    System.IDisposable.Dispose
    IL_008A:  nop         
    IL_008B:  endfinally  
    IL_008C:  nop   
    ...




    首先可以看到很多方法调用,并且在循环体内部每次都要调用方法MoveNext。最后可以看到,有end finally,意味着这个循环外部包了一层try-finally。从IL来看,foreach要比for慢的多了。


    现在来看StopWatch的执行结果。

    for loop takes : 764538
    for loop takes : 1311252




    for几乎快了一倍。 


    结论:编程语言提供的关键字是为了解决某种问题而存在,需要对具体的业务场景进行判断再决定,有关性能方面,一定要拿出数据说话。


沪ICP备19023445号-2号
友情链接