title author date CreateTime categories
C# 循环的判断会进来几次
lindexi
2019-08-31 16:55:58 +0800
2018-06-14 08:59:26 +0800
C#

最近有小伙伴告诉我,在循环的判断条件只会计算一次,本金鱼不相信,于是就做了测试,本文记录我做的测试。

先来写一个简单的代码, 就一个循环,循环的判断是从一个函数获取值

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. var meepeMorcear = new MeepeMorcear();
  6. meepeMorcear.BirmeruLerrayjairbay();
  7. }
  8. }
  9.  
  10. class MeepeMorcear
  11. {
  12. public void BirmeruLerrayjairbay()
  13. {
  14. for (int i = 0; i < DaydrearNenawerlai(); i++)
  15. {
  16. Console.WriteLine("第" +i.ToString()+"个逗比");
  17. }
  18. }
  19.  
  20. public int DaydrearNenawerlai()
  21. {
  22. Console.WriteLine("进入");
  23. return 10;
  24. }
  25. }

通过 Main 调用 BirmeruLerrayjairbay ,这个函数里面的 for 判断是 DaydrearNenawerlai 拿到一个值,我尝试在 release 运行,结果每个判断都需要进入 DaydrearNenawerlai 函数,请看输出

  1. 进入
  2. 0个逗比
  3. 进入
  4. 1个逗比
  5. 进入
  6. 2个逗比
  7. 进入
  8. 3个逗比
  9. 进入
  10. 4个逗比
  11. 进入
  12. 5个逗比
  13. 进入
  14. 6个逗比
  15. 进入
  16. 7个逗比
  17. 进入
  18. 8个逗比
  19. 进入
  20. 9个逗比

也就是在 Debug 或 Release 下,for 里面的判断都是需要执行,所以在 for 里的判断如果写了很长的计算,那么就会在每次循环都需要重新计算。即使每次计算出来的值都是一样,也需要重新计算。

所以这样看起来性能不如这样写,使用一个临时的变量获取判断的值

  1. public void BirmeruLerrayjairbay()
  2. {
  3. var mowraiTepalor = DaydrearNenawerlai();
  4. for (int i = 0; i < mowraiTepalor; i++)
  5. {
  6. Console.WriteLine("第" +i.ToString()+"个逗比");
  7. }
  8. }

但是很快,另一个小伙伴告诉我,你把输出去掉,然后使用断点,你再看看

我添加了断点,在断点输出 123 然后运行

这时我发现运行没有输出 123 也就是函数没有进来,我再次添加断点,跟着函数也没有访问

所以这时的 DaydrearNenawerlai 函数就被优化掉了

我和一个小伙伴说了这个问题,他说是被 IL 优化了,我一点不相信,所以我就去看 IL 代码

从下面的代码

  1. public void BirmeruLerrayjairbay()
  2. {
  3. for (int i = 0; i < DaydrearNenawerlai(); i++)
  4. {
  5. Console.WriteLine("第" +i.ToString()+"个逗比");
  6. }
  7. }
  8.  
  9. /// <summary>
  10. /// 进入lindexi.github.io可以看到更多博客
  11. /// </summary>
  12. /// <returns></returns>
  13. public static int DaydrearNenawerlai()
  14. {
  15. return 10;
  16. }

转 IL 可以看到下面代码,我会在 IL 添加很多注释,所以很容易看懂。

  1. .method public hidebysig instance void
  2. BirmeruLerrayjairbay() cil managed
  3. {
  4. .maxstack 3
  5. .locals init (
  6. [0] int32 i
  7. )
  8. // 第 23 行 18 个字符到 27 个字符
  9. // [23 18 - 23 27]
  10. IL_0000: ldc.i4.0
  11. // 定义 i ,代码的 int i = 0;
  12. IL_0001: stloc.0 // i
  13. IL_0002: br.s IL_0023
  14. // 这里就是进入循环 for ,在 IL 不管 for 还是 while 都是差不多
  15. // start of loop, entry point: IL_0023
  16. // [25 17 - 25 60]
  17. // 下面这个代码就是 Console.WriteLine("第" +i.ToString()+"个逗比"); 从代码可以看到
  18. // 需要先申请"第"
  19. IL_0004: ldstr "第"
  20. // 然后把 i 放入栈
  21. IL_0009: ldloca.s i
  22. // 调用 int.ToString ,使用的是实例的方法
  23. IL_000b: call instance string [mscorlib]System.Int32::ToString()
  24. // 把"个逗比"放入栈
  25. IL_0010: ldstr "个逗比"
  26. // 调用字符串组合方法,组合三个字符串,返回一个字符串。
  27. // 把刚才入栈三个字符串出栈,返回的字符串入栈
  28. IL_0015: call string [mscorlib]System.String::Concat(string, string, string)
  29. // 调用 Console.WriteLine ,从栈拿到一个字符串输出
  30. IL_001a: call void [mscorlib]System.Console::WriteLine(string)
  31. // 下面是 i++ 代码
  32. // [23 55 - 23 58]
  33. // 将指定索引处的局部变量加载到计算堆栈上,这里的索引是 0 ,在代码的变量是 i 所以把 i 加载到计算堆栈
  34. IL_001f: ldloc.0 // i
  35. // 将整数值 1 作为 int32 推送到计算堆栈上
  36. IL_0020: ldc.i4.1
  37. // 从堆栈出栈两个数值进行相加,返回的值放在栈
  38. IL_0021: add
  39. // 从计算堆栈的顶部弹出当前值并将其存储到指定索引处的局部变量列表中,这里索引是 0 ,在代码的变量是 i ,所以 i = i + 1 的代码就是这样做
  40. IL_0022: stloc.0 // i
  41. // 从堆栈加载 i ,把 i 入栈
  42. // [23 29 - 23 53]
  43. IL_0023: ldloc.0 // i
  44. // 调用方法 DaydrearNenawerlai 拿到返回值
  45. IL_0024: call int32 MuhoubearWhedoofi.MeepeMorcear::DaydrearNenawerlai()
  46. // 如果第一个值小于第二个值,则将控制转移到目标指令,这里的第一个值就是 i ,第二个值就是 DaydrearNenawerlai 的返回值。跳转到标签 IL_0004 ,如果没有小于,就继续代码。
  47. IL_0029: blt.s IL_0004
  48. // end of loop
  49. // [27 9 - 27 10]
  50. IL_002b: ret
  51. } // end of method MeepeMorcear::BirmeruLerrayjairbay
  52. .method public hidebysig static int32
  53. DaydrearNenawerlai() cil managed
  54. {
  55. .maxstack 8
  56. // 把一个值 放入堆栈,放入的是 10 ,然后从栈拿到值返回
  57. // [36 13 - 36 23]
  58. IL_0000: ldc.i4.s 10 // 0x0a
  59. IL_0002: ret
  60. } // end of method MeepeMorcear::DaydrearNenawerlai

从上面代码可以发现,实际 DaydrearNenawerlai 没有被优化掉,还是有这个方法。

参见:.net IL 指令速查 - 飞鸟123 - 博客园

2019-8-31-C#-循环的判断会进来几次的更多相关文章

  1. C# 循环的判断会进来几次

    最近有小伙伴告诉我,在循环的判断条件只会计算一次,本金鱼不相信,于是就做了测试,本文记录我做的测试. 先来写一个简单的代码, 就一个循环,循环的判断是从一个函数获取值 class Program { ...

  2. Java 变量、循环、判断

    粗糙笔记不喜勿喷 Java 8大基本类型 第一类:逻辑型(boolean) 1.boolean类型只存在true(真),false(假)两种形式 例: boolean a=true; boolean ...

  3. mysql存储过程查询结果循环遍历 判断 赋值 游标等基本操作

    一.首先说下本篇博客所实现功能的背景和功能是怎样的: 背景:因为公司项目开始迁移新平台项目,所以以前的平台老数据以及订单信息需要拆分表,而且需要业务逻辑来分析以前的订单表,来拆分成另外的几个新表,包括 ...

  4. Angular4.x 创建组件|绑定数据|绑定属性|数据循环|条件判断|事件|表单处理|双向数据绑定

    Angular4.x 创建组件|绑定数据|绑定属性|数据循环|条件判断|事件|表单处理|双向数据绑定 创建 angular 组件 https://github.com/angular/angular- ...

  5. “全栈2019”Java多线程第九章:判断线程是否存活isAlive()详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  6. smarty基本用法,循环,判断

    require './smarty/Smarty.class.php'; $sm = new Smarty; $sm->setTemplateDir("./dir");//设 ...

  7. .NET Core CSharp初级篇 1-2 循环与判断

    .NET Core CSharp初级篇 1-2 本节内容循环与判断 循环 循环是一个在任何语言都是极为重要的语法,它可以用于很多东西,例如迭代数组等等.在C#中,语法层面的循环有:for , fore ...

  8. agentzh 的 Nginx 教程(版本 2019.07.31)

    agentzh 的 Nginx 教程(版本 2019.07.31) agentzh 的 Nginx 教程(版本 2019.07.31) https://openresty.org/download/a ...

  9. Beego模板 循环和判断几个例子

    Beego模板 循环和判断几个例子 Beego的前端几乎是另一种语言.一些循环.判断,不细看文档真的做不出来. 0. Beego的View模板语法规则: beego前端(view)统一使用了 {{ 和 ...

随机推荐

  1. 路由的配置,侧边栏类名与url的结合运用

    var url_array = document.location.pathname.split("/"); s1 = url_array[1]; s2 = url_array[2 ...

  2. vue 编写插件

    1.    将插件逻辑封装成一个对象  最后在install编写业务代码暴露给Vue对象 好处: 可以添加任意参数在这个对象上 方便将install函数封装的更加精简 可拓展性也比较高 2.  将所有 ...

  3. Web充斥着存在漏洞的过期JavaScript库

    虽然使用第三方软件库通常会降低开发的时间,但同时也会增加网站暴露出的攻击表面,对此我们应有充分的认识.因此需要保持第三方软件库的最新版本依赖,以便从安全更新中获益.即便如此,一份近期研究表明,在Ale ...

  4. Ceisum官方教程3 -- 空间数据可视化

    原文地址:https://cesiumjs.org/tutorials/Visualizing-Spatial-Data/ 这篇教程教你如何使用Cesium的Entity API去绘制空间数据,如点, ...

  5. Struts2启动问题:ClassNotFoundException: org...dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

    错误信息: java.lang.ClassNotFoundException: org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExec ...

  6. 再谈MFC学习——模态对话框的数据传递

    学习c++的目的就是为了使用封装好的类.而最最经典的封装类当然是微软的MFC窗体程序类. 学习MFC编程之前要学习c++的主要知识,掌握c++的基本编程思想. 以下就看下我学习的MFC模态对话框的数据 ...

  7. C# 全局Hook在xp上不回调

    最近做了个捕捉全局鼠标,获取目标窗体内的控件文本信息,点击的按钮信息.用的全局钩子.在win10上运行正常,部署到xp系统上就没有反应.查了些资料,解决了此问题. 原本安装钩子的写法如下: Nativ ...

  8. tortoisegit如何删除远程分支

    图片来自:https://zhidao.baidu.com/question/134542616148384045.html

  9. Luogu P1073 最优贸易(最短路)

    P1073 最优贸易 题意 题目描述 \(C\)国有\(n\)个大城市和\(m\)条道路,每条道路连接这\(n\)个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这\(m\)条道路中有 ...

  10. TZ_06_SpringMVC_拦截器的配置

    1. 拦截器的概述 1>. SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术. 2>. 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方 ...