黑马程序员技术交流社区

标题: 第一帖switch语句和if语句效率对比 [打印本页]

作者: 黄茂霖    时间: 2013-4-24 16:43
标题: 第一帖switch语句和if语句效率对比
本帖最后由 shenqi 于 2013-4-25 07:12 编辑

switch和if-else相比,由于使用了Binary Tree算法,绝大部分情况下switch会快一点,除非是if-else的第一个条件就为true.
一本叫做CSAPP的书,关于switch问题的解答。
这是一段C代码:
有JAVA基础,这段代码看起来应该不难。
  1. int main()
  2. {
  3.     unsigned int i,j;
  4.     i=3;
  5.     switch (i)
  6.     {
  7.     case 0:
  8.         j=0;
  9.         break;
  10.     case 1:
  11.         j=1;
  12.         break;
  13.     case 2:
  14.         j=2;
  15.         break;
  16.     case 3:
  17.         j=3;
  18.         break;
  19.     case 4:
  20.         j=4;
  21.         break;
  22.     default:
  23.         j=10;
  24.         break;
  25.     }
  26. }
复制代码
这里涉及到了汇编语言的知识,有汇编基础的就比较容易理解。
用GCC汇编出来的代码如下:
  1. .file "shiyan.c"
  2. .text
  3. .globl main
  4. .type main, @function
  5. main:
  6. leal 4(%esp), %ecx
  7. andl $-16, %esp
  8. pushl -4(%ecx)
  9. pushl %ebp
  10. movl %esp, %ebp
  11. pushl %ecx
  12. subl $20, %esp
  13. movl $3, -8(%ebp)
  14. cmpl $4, -8(%ebp)
  15. ja .L2
  16. movl -8(%ebp), %eax
  17. sall $2, %eax
  18. movl .L8(%eax), %eax
  19. jmp *%eax
  20. .section .rodata
  21. .align 4
  22. .align 4
  23. .L8:
  24. .long .L3
  25. .long .L4
  26. .long .L5
  27. .long .L6
  28. .long .L7
  29. .text
  30. .L3:
  31. movl $0, -12(%ebp)
  32. jmp .L11
  33. .L4:
  34. movl $1, -12(%ebp)
  35. jmp .L11
  36. .L5:
  37. movl $2, -12(%ebp)
  38. jmp .L11
  39. .L6:
  40. movl $3, -12(%ebp)
  41. jmp .L11
  42. .L7:
  43. movl $4, -12(%ebp)
  44. jmp .L11
  45. .L2:
  46. movl $10, -12(%ebp)
  47. .L11:
  48. addl $20, %esp
  49. popl %ecx
  50. popl %ebp
  51. leal -4(%ecx), %esp
  52. ret
  53. .size main, .-main
  54. .ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
  55. .section .note.GNU-stack,"",@progbits
复制代码
在上面的汇编代码中我们可以很清楚的看到switch部分被分配了一个连续的查找表,switch case中不连续的部分
也被添加上了相应的条目,switch表的大小不是根据case语句的多少,而是case的最大值的最小值之间的间距。
在选择相应 的分支时,会先有一个cmp子句,如果大于查找表的最大值,则跳转到default子句。


相比于if-else结构,switch的效率绝对是要高很多的,但是switch使用查找表的方式决定了case的条件必须是一个
连续的常量。而if-else则可以灵活的多。

但是尽管如此,我们强大的sun公司把switch和if的性能优化得不相上下。
有同学做了简单的测试:

对有多个条件式的switch和if做比较,发现两者的效率几乎相同,if的效率甚至高于switch;<测试环境sun jdk6.1.13>
     40个条件式的测试,测试1000 0000次,if耗时219ms, switch耗时234ms,平均都在4-5k/s;
     30个条件式的测试,测试1000 0000次,if耗时188 switch耗时172平均都在5-6kw/s,
     20个条件式,测试1000 0000次,if耗时109mswitch耗时125ms,平均在8-9kw/s

  1. private static void testSitchAndIf() {
  2.                 int testCount = 10000000;
  3.                 int flag = 0;

  4.                 Random random = new Random(testCount);
  5.                 int[] flags = new int[testCount];
  6.                 for (int i = 0; i < testCount; i++) {
  7.                         flags[i] = random.nextInt() + 1;
  8.                 }
  9.                 // 先统一取一遍值,保证测试都用缓存值
  10.                 for (int i = 0; i < testCount; i++) {
  11.                         flag = flags[i];
  12.                 }
  13.                 long time1 = System.currentTimeMillis();
  14.                 for (int i = 0; i < testCount; i++) {
  15.                         // flag = random.nextInt() + 1;
  16.                         flag = flags[i];
  17.                         if (flag == 1) {
  18.                         } else if (flag == 2) {
  19.                         } else if (flag == 3) {
  20.                         } else if (flag == 4) {
  21.                         } else if (flag == 5) {
  22.                         } else if (flag == 6) {
  23.                         } else if (flag == 7) {
  24.                         } else if (flag == 8) {
  25.                         } else if (flag == 9) {
  26.                         } else if (flag == 10) {
  27.                         } else if (flag == 11) {
  28.                         } else if (flag == 12) {
  29.                         } else if (flag == 13) {
  30.                         } else if (flag == 14) {
  31.                         } else if (flag == 15) {
  32.                         } else if (flag == 16) {
  33.                         } else if (flag == 17) {
  34.                         } else if (flag == 18) {
  35.                         } else if (flag == 19) {
  36.                         } else if (flag == 20) {
  37.                         } else if (flag == 21) {
  38.                         } else if (flag == 22) {
  39.                         } else if (flag == 23) {
  40.                         } else if (flag == 24) {
  41.                         } else if (flag == 25) {
  42.                         } else if (flag == 26) {
  43.                         } else if (flag == 27) {
  44.                         } else if (flag == 28) {
  45.                         } else if (flag == 29) {
  46.                         } else if (flag == 30) {
  47.                         }
  48.                         // else if(flag == 31){}
  49.                         // else if(flag == 32){}
  50.                         // else if(flag == 33){}
  51.                         // else if(flag == 34){}
  52.                         // else if(flag == 35){}
  53.                         // else if(flag == 36){}
  54.                         // else if(flag == 37){}
  55.                         // else if(flag == 38){}
  56.                         // else if(flag == 39){}
  57.                         // else if(flag == 40){}
  58.                 }

  59.                 long time2 = System.currentTimeMillis();
  60.                 for (int i = 0; i < testCount; i++) {
  61.                         flag = flags[i];
  62.                         switch (flag) {
  63.                         case 1:
  64.                                 break;
  65.                         case 2:
  66.                                 break;
  67.                         case 3:
  68.                                 break;
  69.                         case 4:
  70.                                 break;
  71.                         case 5:
  72.                                 break;
  73.                         case 6:
  74.                                 break;
  75.                         case 7:
  76.                                 break;
  77.                         case 8:
  78.                                 break;
  79.                         case 9:
  80.                                 break;
  81.                         case 10:
  82.                                 break;
  83.                         case 11:
  84.                                 break;
  85.                         case 12:
  86.                                 break;
  87.                         case 13:
  88.                                 break;
  89.                         case 14:
  90.                                 break;
  91.                         case 15:
  92.                                 break;
  93.                         case 16:
  94.                                 break;
  95.                         case 17:
  96.                                 break;
  97.                         case 18:
  98.                                 break;
  99.                         case 19:
  100.                                 break;
  101.                         case 20:
  102.                                 break;
  103.                         case 21:
  104.                                 break;
  105.                         case 22:
  106.                                 break;
  107.                         case 23:
  108.                                 break;
  109.                         case 24:
  110.                                 break;
  111.                         case 25:
  112.                                 break;
  113.                         case 26:
  114.                                 break;
  115.                         case 27:
  116.                                 break;
  117.                         case 28:
  118.                                 break;
  119.                         case 29:
  120.                                 break;
  121.                         case 30:
  122.                                 break;
  123.                         // case 31: break;
  124.                         // case 32: break;
  125.                         // case 33: break;
  126.                         // case 34: break;
  127.                         // case 35: break;
  128.                         // case 36: break;
  129.                         // case 37: break;
  130.                         // case 38: break;
  131.                         // case 39: break;
  132.                         // case 40: break;
  133.                         // case 41: break;
  134.                         }
  135.                 }

  136.                 long time3 = System.currentTimeMillis();
  137.                 System.out.println("loop count:" + testCount);
  138.                 System.out.println("if consume time:" + (time2 - time1) + ",avg:"
  139.                                 + testCount / (time2 - time1) * 1000);
  140.                 System.out.println("switch consume time:" + (time3 - time2) + ",avg:"
  141.                                 + testCount / (time3 - time2) * 1000);
  142.         }
复制代码
总结:
      1 经过jdk的改进,目前switch和if的性能上差别微乎其微
      2 条件式的多少对于一般应用的整体性能来说,影响也非常小。
      3 影响效率的最大因子是条件式的数量,而非if或switch



作者: 曹睿翔    时间: 2013-4-24 16:51
代码贴的还有问题(代码不能加粗,设置color和size),稍微修改下就行,我再看看
还不错,把标题前边加上“第一帖”
作者: 黄茂霖    时间: 2013-4-25 07:13
曹睿翔 发表于 2013-4-24 16:51
代码贴的还有问题(代码不能加粗,设置color和size),稍微修改下就行,我再看看
还不错,把标题前边加上“ ...

修改好了!你看行吗:P
作者: 曹睿翔    时间: 2013-4-25 07:21
不错,关于第一天收集你能再领一个任务不,看你基础不错,是想深入整理switch还是想整理数组?哈哈
作者: 黄茂霖    时间: 2013-4-25 07:27
曹睿翔 发表于 2013-4-25 07:21
不错,关于第一天收集你能再领一个任务不,看你基础不错,是想深入整理switch还是想整理数组?哈哈 ...

恩!可以啊!~数组和switch都可以
作者: 曹睿翔    时间: 2013-4-25 07:32
shenqi 发表于 2013-4-25 07:27
恩!可以啊!~数组和switch都可以

那就都有分,今天整理吧,明天该出下一步的活动,将全新改版,欢迎继续领取
ps:我需要看看你整理的如何才选择是否收录,建议深入点,要有自己总结,我看重的是自己总结(我一般会先搜一下知识,看看相似度是否很大),哈哈,要求有点高了,数组这块还是不好整理的,李刚的疯狂讲义可是用了一章(不求过于深入,你把握吧),慢慢来
作者: Just_Only    时间: 2013-4-25 09:17
总结的很好的 不错的
作者: 刘凯    时间: 2013-4-25 19:39
我可以说,楼主的这貌似在哪见过么,可能不是原模原样,但一眼就感觉类似, 还有 楼主帖汇编 根本就没人看的懂啊,,,,

我是说,这个活动很好,楼主的积极参与也很好,但是最好是自个先搞明白这个知识点以后,用自己的,且容易让别人理解的,简洁,且可以让我等众多活跃在论坛里的菜鸟级的人物看的明白的语言和讲解来发帖。毕竟让我们能够学到真正的东西才是这个活动的最终目的。

不够还是顶了。 不过还是说不要为了任务而任务啊 ,   

小弟近期时间比较紧张,不过也有些自个在其他途径学到的小知识点,和视频学习中的一些小见解, 待啥时候不想学的时候,也拿出来整理下好了 、不过是些比较散的东西
作者: HM刘俊    时间: 2013-4-26 15:32
整理的很好啊,那我就不发了。。。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2