if形容办事效率高的语句的效率问题

403 Forbidden
403 Forbidden32409人阅读
编程杂谈(10)
switch与if..else 的执行的效率问题&今天读一前辈的程序,发现其在串口中断里面为了分析协议的报文类型,在中断函数里面使用if..else语句。因为报文类型在现在看来只有两种,以后有可能还会增加,不确定。&本人以为这样用有些不妥,为什么不用switch语句呢?猜想是不是因为效率方面的考虑呢,毕竟我们应该尽量是中断的处理代码更加简洁,时间效率更高才好。&所以本人就查找相关资料,资料显示switch语句反而比ifelse的执行效率要高。&下面来详细描述switch与ifelse的区别。&switch...case与if...else的根本区别在于,switch...case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的。从而,switch...case不用像if...else那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。具体地说,switch...case会生成一份大小(表项数)为最大case常量+1的跳表,程序首先判断switch变量是否大于最大case 常量,若大于,则跳到default分支处理;否则取得索引号为switch变量大小的跳表项的地址(即跳表的起始地址+表项大小*索引号),程序接着跳到此地址执行,到此完成了分支的跳转。//
int main(){&unsigned int i,j;&i=3;&switch (i)&{&&case 0:&&j=0;&&&&case 1:&&j=1;&&&&case 2:&&j=2;&&&&case 3:&&j=3;&&&&case 4:&&j=4;&&&&default:&&j=10;&&&}
用gcc编译器,生成汇编代码(不开编译器优化)&.file&"shiyan.c"&.text.globl main&.type&main, @functionmain:&leal&4(%esp), %ecx&andl&$-16, %esp&pushl&-4(%ecx)&pushl&%ebp&movl&%esp, %ebp&pushl&%ecx&subl&$20, %esp&movl&$3, -8(%ebp)&cmpl&$4, -8(%ebp)&ja&.L2&movl&-8(%ebp), %eax&sall&$2, %eax&movl&.L8(%eax), %eax&jmp&*%eax&.section&.rodata&.align 4&.align 4.L8:&.long&.L3&.long&.L4&.long&.L5&.long&.L6&.long&.L7&.text.L3:&movl&$0, -12(%ebp)&jmp&.L11.L4:&movl&$1, -12(%ebp)&jmp&.L11.L5:&movl&$2, -12(%ebp)&jmp&.L11.L6:&movl&$3, -12(%ebp)&jmp&.L11.L7:&movl&$4, -12(%ebp)&jmp&.L11.L2:&movl&$10, -12(%ebp).L11:&addl&$20, %esp&popl&%ecx&popl&%ebp&leal&-4(%ecx), %esp&ret&.size&main, .-main&.ident&"GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"&.section&.note.GNU-stack,"",@progbits
由此看来,switch有点以空间换时间的意思,而事实上也的确如此。1.当分支较多时,当时用switch的效率是很高的。因为switch是随机访问的,就是确定了选择值之后直接跳转到那个特定的分支,但是if。。else是遍历所以得可能值,知道找到符合条件的分支。如此看来,switch的效率确实比ifelse要高的多。2.由上面的汇编代码可知道,switch...case占用较多的代码空间,因为它要生成跳表,特别是当case常量分布范围很大但实际有效值又比较少的情况,switch...case的空间利用率将变得很低。3.switch...case只能处理case为常量的情况,对非常量的情况是无能为力的。例如 if (a & 1 && a & 100),是无法使用switch...case来处理的。所以,switch只能是在常量选择分支时比ifelse效率高,但是ifelse能应用于更多的场合,ifelse比较灵活。
由此看来,上面前辈的中断处理程序中用switch是比较合适的,即节省了时间,而且对于以后程序的扩展也是很方便。因为报文类型这个值基本上都是用整形常量来表示的。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:116274次
积分:1386
积分:1386
排名:千里之外
原创:30篇
转载:22篇
评论:33条
(1)(1)(3)(1)(4)(1)(1)(3)(3)(4)(3)(3)(5)(2)(10)(3)(1)(1)(2)快速和慢速的 if 语句:现代处理器的分支预测 - 文章 - 伯乐在线
& 快速和慢速的 if 语句:现代处理器的分支预测
语句的性能取决于它的判断条件是否拥有可预测模式,你知道吗?如果条件始终为真或者始终为假,处理器内的分支预测逻辑会选择该模式。此外,如果该模式不可预测,if语句的开销将更大。本文将解释为什么现代处理器要这样做。
接下来,我们在不同条件下测试该循环的性能:
for (int i = 0; i & i++) if (&condition&) sum++;
for (int i = 0; i & max; i++) if (&condition&) sum++;
以下是不同真-假模式下该循环的耗时:
Pattern/模式
(i & 0x) == 0
T repeated
(i & 0xffffffff) == 0
F repeated
(i & 1) == 0
TF alternating
(i & 3) == 0
TFFFTFFF…
(i & 2) == 0
TTFFTTFF…
(i & 4) == 0
TTTTFFFFTTTTFFFF…
(i & 8) == 0
8T 8F 8T 8F …
(i & 16) == 0
16T 16F 16T 16F …
语句在“坏”真-假模式下比在“好”模式下慢了近六倍!当然,模式的好坏取决于编译器产生的具体指令集和具体处理器。
让我们看看处理器计数器
了解处理器如何利用时间的一种方式是查看硬件计数器。为帮助性能调试,现代处理器在执行代码时跟踪各种计数器:执行指令的数量,各种类型内存访问的数量,遇到分支的数量等等。要读取计数器,你需要像,或者类似的工具。
为了验证我们观察到的性能降低是由于if语句造成的,我们可以查看分支预测错误计数器:
最糟糕的模式(TTFFTTFF…)将导致744次分支预测错误,而好的模式下大约只有10次。无疑坏情况花费最长的1.67秒,而好模式下仅花费大约300毫秒!
接下来分析分支预测做了什么,以及为什么它会对处理器性能有这么大影响。
分支预测扮演什么角色?
为解释分支预测是什么以及为何会影响性能参数,首先我们需要了解一下现代处理器的工作原理。为了执行每条指令,CPU会经历以下这些(可能更多)步骤:
1. 取指:读取下一条指令。
2. 译码:完成指令的翻译。
3. 执行:执行指令。
4. 回写:保存结果到内存。
一个重要的优化是流水线阶段可同时处理不同指令。那么,在读取一条指令时,第二条指令正在译码,第三条指令正在执行,而第四条指令正在回写。现代处理器有10-31级流水线(例如,Pentium 4 Prescott有),为优化性能,保持所有阶段尽可能一直工作非常重要。
图像来源于
分支(即条件跳转)给处理器流水线提出一个难题。在获取一条指令后,处理器需要获取下一条指令。但是下一条指令有两种可能!处理器不确定取哪一条,直到分支条件指令执行到流水线结束。
与暂停流水线直至分支条件指令完全执行不同,现代处理器尝试预测是否需要进行跳转。然后处理器会读取它认为正确的下一条指令。如果预测出错,处理器会丢弃在流水线上执行了部分的指令。在维基页面上,可以看到处理器获取并解释分支统计数据的一些经典技术。
现代分支预测器适合分析简单模式:全真,全假,真-假交替等。但是如果模式超出分支预测器的预测,性能影响将会非常严重。幸好大部分分支很容易预测,比如下面两个高亮的例子:
int SumArray(int[] array) {
if (array == null) throw new ArgumentNullException("array");
int sum=0;
for(int i=0; i&array.L i++) sum += array[i];
int SumArray(int[] array) {&&&&if (array == null) throw new ArgumentNullException("array");&&&&&int sum=0;&&&&for(int i=0; i&array.Length; i++) sum += array[i];&&&&return sum;}
第一个高亮的条件检查输入的合法性,那么该分支很少会执行。第二条高亮条件是循环终止条件。这也几乎总是朝着一个方向走,除非处理的数组非常短。所以,在这些情况下,与大多数情况类似,处理器分支预测逻辑可以有效防止处理器流水线暂停。
更新和说明
本文被收录,并且在中获得不少关注。我会对下面的问题、评论和批评进行回复。
首先,关于分支预测优化通常是个坏主意的评论:我同意。我没有在文中任何地方争辩说你应该尝试为分支预测优化你的代码。对于绝大部分高级语言代码,我甚至不敢想象你们是如何做到的。
第二点,有人担心除常量值,是不是不同情况下执行的指令都不一样。它们是一样的——我查看了JIT-ted汇编。如果你想要了解JIT-ted汇编代码或者C#源代码,请给我发封邮件,我会把他们发送给你。(我在这里不贴出代码,因为我不想让更新过于庞大。)
第三点,另一个问题是关于TTFF*模式效率极低。TTFF*模式周期很短,这应该是一个简单的分支跳转预测算法的应用场景。
然而,问题在于现代处理器不单独跟踪每一条分支指令历史。相反,它们要么跟踪所有分支的全局历史,要么它们有一些历史插槽,每一个都被多分支指令共享。或者,它们可以使用这些技巧与其他技术组合。
所以,if语句中的TTFF模式在到达分支预测器时可能并不是TTFF模式。它可能会和其他分支(在for循环体中有两个分支指令)交错在一起,可能和其他模式非常接近。但是,我并不是处理器运作方面的专家,如果读本文的人有不同处理器(尤其是我测试用的Intel Core2)如何运转的权威参考,请在评论区告诉我。
关于作者:
可能感兴趣的话题
不明觉厉,我是根本看不懂。
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2016 伯乐在线Java基础(19)
switch和if-else相比,由于使用了Binary Tree算法,绝大部分情况下switch会快一点,除非是if-else的第一个条件就为true.
原理:switch...case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的。从而,switch...case不用像if...else那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。
switch 使用:
switch(表达式)整型或可以转变为整型的值(byte、short、char和int类型)和枚举类型,long类型不能。case 后面只能为常数或常量,不能为变量。执行的过程中,如果遇到break语句,则跳出switch语句。
分支较少的时候用if-esle,分支多的时候switch会比较清晰。
编译器编译switch与编译if...else...不同。不管有多少case,都直接跳转,不需逐个比较查询
(根据网上的代码)
/* $begin switch-c */
int switch_eg(int x)
int result =
switch (x) {
result *= 13;
result += 10;
/* Fall through */
result += 11;
result = 0;
/* $end switch-c */
用GCC汇编出来的代码如下:
&switch.c&
gcc2_compiled.:
.globl switch_eg
switch_eg,@function
switch_eg:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%edx
leal -100(%edx),%eax
cmpl ,%eax
jmp *.L10(,%eax,4)
.p2align 4,,7
.p2align 4,,7
leal (%edx,%edx,2),%eax
leal (%edx,%eax,4),%edx
.p2align 4,,7
addl ,%edx
addl ,%edx
.p2align 4,,7
imull %edx,%edx
.p2align 4,,7
xorl %edx,%edx
movl %edx,%eax
movl %ebp,%esp
switch_eg,.Lfe1-switch_eg
&GCC: (GNU) 2.95.3
(release)& switch&& 只计算一次值&& 然后都是test ,jmp,&&&&&
if...else&& 是每个条件都要计算一遍的.&
链接:另外的解释:http://bbs.csdn.net/topics/
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:25777次
积分:1015
积分:1015
排名:千里之外
原创:78篇
(6)(2)(1)(1)(1)(1)(3)(6)(48)(1)(17)!条件 && 语句;
这样来达到if语句的效果_c语言吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:503,065贴子:
!条件 && 语句;
这样来达到if语句的效果收藏
这样效率会高点吗?
告别死工资:送150美金,可提取
&和&&不分么。
这种"效率"不需要你担心, 编译器不傻.
简单代码自己看下汇编应该不难int func(int a, int b){   if (a && b) {    return 0;
  } else {
    return 1;
  }}汇编:func:.LFB2:
%rbp.LCFI0:
%rsp, %rbp.LCFI1:
%edi, -4(%rbp)
%esi, -8(%rbp)
$0, -4(%rbp)
$0, -8(%rbp)
$0, -12(%rbp)
$1, -12(%rbp).L3:
-12(%rbp), %eax
 ret逻辑运算怎么实现的尽在不言中了吧?
基本不可能会高。效率和可读性的矛盾不太多,编译器会尽可能做优化。
啊咧,少了两楼?
(sp,12),r0
r2,(sp,12)
.LBB0_1.LBB0_1:
.LBB0_2.LBB0_2:
(sp,16),r0
.LBB0_4.LBB0_3:
(sp,16),r0.LBB0_4:
r0,(sp,16)
  ret clang风格的没优化……不过没编X86后端,所以凑合看吧
@怪兽大战魔人if(!fp);if(fp==NULL);哪个效率高?
你们真猛。。
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或}

我要回帖

更多关于 检测sql语句效率 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信