阅读更多

6顶
2踩

企业架构

转载新闻 代码执行的效率

2012-07-13 17:34 by 正式记者 小枫晚亭 评论(4) 有8838人浏览
要进行性能调优,首先就要了解操作系统性能,找到程序中的Hotspot,也就是被调用最多的热点地方,只要能够好好优化一下这些地方,性能就会有质的提高。这里给大家用三个网上关于代码执行效率的例子来说明一下。

第一个例子

PHP中Getter和Setter的效率来源reddit

这个例子比较简单,可以简单了解一下。

考虑下面的PHP代码:我们可看到,使用Getter/Setter的方式,性能要比直接读写成员变量要差一倍以上。

<?php
    //dog_naive.php
 
    class dog {
        public $name = "";
        public function setName($name) {
            $this-&gt;name = $name;
        }
        public function getName() {
            return $this-&gt;name;
        }
    }
 
    $rover = new dog();
        //通过Getter/Setter方式
    for ($x=0; $x<10; $x++) {
        $t = microtime(true);
        for ($i=0; $i<1000000; $i++) {
            $rover->setName("rover");
            $n = $rover->getName();
        }
        echo microtime(true) - $t;
        echo "\n";
    }
        //直接存取变量方式
        for ($x=0; $x<10; $x++) {
        $t = microtime(true);
        for($i=0; $i<1000000; $i++) {
            $rover->name = "rover";
            $n = $rover->name;
        }
        echo microtime(true) - $t;
        echo "\n";
    }
?>

这个并没有什么稀奇,因为有函数调用的开销,函数调用需要压栈出栈,需要传值,有时还要需要中断,要干的事太多了。所以,代码多了,效率自然就慢了。所有的语言都都是这样,这就是为什么C++要引入inline的原因。而且Java在打开优化的时候也可以优化之。但是对于动态语言来说,这个事就变得有点困难了。

你可能会以为使用下面的代码(Magic Function)会好一些,但实际其性能更差。
class dog {
    private $_name = "";
    function __set($property,$value) {
        if($property == 'name') $this->_name = $value;
    }
    function __get($property) {
        if($property == 'name') return $this->_name;
    }
}

动态语言的效率从来都是一个问题,如果你需要PHP有更好的性能,你可能需要使用FaceBook的HipHop来把PHP编译成C语言。

第二个例子

为什么Python程序在函数内执行得更快?来源StackOverflow

考虑下面的代码,一个在函数体内,一个是全局的代码。

函数内的代码执行效率为 1.8s
def main():
    for i in xrange(10**8):
        pass
main()

函数体外的代码执行效率为 4.5s
for i in xrange(10**8):
    pass

不用太纠结时间,只是一个示例,我们可以看到效率差的很多。为什么会这样呢?我们使用 dis module 反汇编函数体内的bytecode 代码,使用 compile builtin 反汇编全局bytecode,我们可以看到下面的反汇编:

Main函数反汇编
13 FOR_ITER                 6 (to 22)
16 STORE_FAST               1 (i)
19 JUMP_ABSOLUTE           13

全局代码
13 FOR_ITER                 6 (to 22)
16 STORE_NAME               1 (i)
19 JUMP_ABSOLUTE           13

我们可以看到,差别就是 STORE_FASTSTORE_NAME,前者比后者快很多。所以,在全局代码中,变量i成了一个全局变量,而函数中的i是放在本地变量表中,所以在全局变量表中查找变量就慢很多。如果你在main函数中声明global i 那么效率也就下来了。原因是,本地变量是存在一个数组中(直到),用一个整型常量去访问,而全局变量存在一个dictionary中,查询很慢。

(注:在C/C++中,这个不是一个问题)

第三个例子

为什么排好序的数据在遍历时会更快?来源StackOverflow

参看如下C/C++的代码:
for (unsigned i = 0; i < 100000; ++i) {
   // primary loop
    for (unsigned j = 0; j < arraySize; ++j) {
        if (data[j] >= 128)
            sum += data[j];
    }
}

如果你的data数组是排好序的,那么性能是1.93s,如果没有排序,性能为11.54秒。差5倍多。无论是C/C++/Java,或是别的什么语言都基本上一样。

这个问题的原因是—— branch prediction分支预判)伟大的stackoverflow给了一个非常不错的解释。

考虑一个铁路分叉,当我们的列车来的时候, 扳道员知道每个分叉通往哪,但不知道这个列车要去哪儿,司机知道要去哪,但是不知道走哪条分叉。所以,我们需要让列车停下来,然后司机和扳道员沟通一下。这样的性能太差了。

所以,我们可以优化一下,那就是猜,我们至少有50%的概率猜对,如果猜对了,火车行驶性能巨高,猜错了,就得让火车退回来。如果我猜对的概率高,那么,我们的性能就会高,否则老是猜错了,性能就很差。

我们的if-else 就像这个铁路分叉一样,下面红箭头所指的就是搬道器。


那么,我们的搬道器是怎么预判的呢?就是使用过去的历史数据,如果历史数据有90%以上的走左边,那么就走左边。所以,我们排好序的数据就更容易猜得对。

排好序的
T = 走分支(条件表达式为true)
N = 不走分支(条件表达式为false)
 
data[] = 0, 1, 2, 3, 4, ... 126, 127, 128, 129, 130, ... 250, 251, 252, ...
branch = N  N  N  N  N  ...   N    N    T    T    T  ...   T    T    T  ...
 
= NNNNNNNNNNNN ... NNNNNNNTTTTTTTTT ... TTTTTTTTTT  (easy to predict)


未排序的
data[] = 226, 185, 125, 158, 198, 144, 217, 79, 202, 118,  14, 150, 177, 182, 133, ...
branch =   T,   T,   N,   T,   T,   T,   T,  N,   T,   N,   N,   T,   T,   T,   N  ...
 
= TTNTTTTNTNNTTTN ...   (completely random - hard to predict)

从上面我们可以看到,排好序的数据更容易预测分支。

对此,那我们怎么办?我们需要在这种循环中除去if-else语句。比如:

我们把条件语句:
if (data[j] >= 128)
sum += data[j];

变成:
int t = (data[j] - 128) >> 31;
sum += ~t & data[j];

“没有分叉”的性能基本上和“排好序有分支”一个样,无论是C/C++,还是Java。

注:在GCC下,如果你使用 -O3 or -ftree-vectorize 编译参数,GCC会帮你优化分叉语句为无分叉语句。VC++2010没有这个功能。

最后,推荐大家一个网站——Google Speed,网站上的有一些教程告诉你如何写出更快的Web程序
  • 大小: 80.6 KB
  • 大小: 9.3 KB
来自: 酷壳
6
2
评论 共 4 条 请登录后发表评论
4 楼 detective1314 2016-08-17 11:30
先能使用,然后再说效率。
3 楼 if(i!=我){} 2012-07-15 23:32
一切脱离应用的所谓优化都是扯淡!!

一个系统有60%代码都好看不好用(效率低),但是它们只会执行一遍或有限次数,那么在它们身上耗费精力去优化纯粹是没事找抽。

编写任何一个程序,首要着力的是稳定清晰的结构、可维护和可扩展,以及实现难度等问题。效率?等系统测试再说吧!
2 楼 damoqiongqiu 2012-07-15 10:34
风云无浪 写道
感觉说了跟没说一样

关于效率的话题,自古以来就是非常扯的
1 楼 风云无浪 2012-07-14 21:17
感觉说了跟没说一样

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • VMware虚拟机的网络设置 - Ice_Dragon的记事本子(From美丽的冰城哈尔滨) - CSDNBlog

    导读: 局域网内实现Windows 2000+Vmware+Red Hat Linux 9.0 访问外网 局域网内实现Windows 2000+Vmware+Red Hat Linux 9.0 访问外网,这个问题我一直没有搞定。 找到了一些有用的文章,希望对你有所帮助 VMware...

  • 选购计算机五个原则,双十一笔记本电脑推荐

    今天的推荐首先从轻薄本开始,这些本子呢定位轻薄,但是性能也并不像过去的轻薄本或者上网本一样只能纯粹的办办公,比如核显如果有HD620、630级别,玩个LOL还是可以的,对于MX150、250这些就更是不在话下了。...

  • 最常用英语单词2000个

    最常用英语单词2000个 1 a [ei, ə] art.一(个);任何一(个);每一(个) 2 I [ai] pron.我 3 ability [əbiliti] n.能力,本领;才能,才智 4 able [eibəl] a.能够…的,得以...

  • 一文看懂:网址,URL,域名,IP地址,DNS,域名解析

    在指出这个问题之前,首先我们要清楚以下几点: 互联网上的所有数据都是存储在主机(服务器)上 互联网中的所有主机都拥有唯一的IP地址 互联网中任意两台主机通信都是通过IP地址来实现 那么了解上述...

  • 梦成真——一个普通学校计算机系学生的出国梦

    2月24 号,周四,正如看手相那个人跟我说的,我这辈子最幸运的日子全和4有关。这一天第一封admit letter到来。至此,我才有勇气去为这一路写一个总结,向自己微笑。。为了这一天,我付出了太多太多。这一路上,帮助...

  • 英语教学系列之PTE与多邻国篇

    7次)听写句子(出现6-7次)阅读单词分辨(出现6-7次)`完形填空`口语看图说词(共出现12张,每次6张,分2次)动物鸟昆虫水果植物/蔬菜职业乐器生活用品衣物饮食朗读句子(出现6次)看问题演讲(出现1次)听问题演讲...

  • 游戏、算法竞赛与退役(流水账版)

    还记得最开始作业是写在本子上的,那好像是我写的最认真的一类作业了,当时不仅好好学,好好写,甚至还会仔细检查一下,生怕出锅HHH 后续新鲜劲儿结束之后,教室就逐渐变成网吧了,因为CL老师带两个年级的班,偶尔会...

  • 电影:雷神

    作为北欧诸神之王奥丁的儿子,托尔很快就会从年迈的父亲那里继承阿斯加德的王位。然而,在他即将加冕的那天,当众神的敌人冰霜巨人违反他们的条约进入宫殿时,托尔做出了残酷的反应。作为惩罚,奥丁将雷神驱逐到地球...

  • 1.1[真的好玩] C++小游戏·跑酷(俗称忍者必须死单机版)

    【一个好人写滴】 代码奉上!!! #include&lt;bits/stdc++.h&gt; #include&lt;windows.h&gt; #include&lt;stdio.h&gt; #include&lt;conio.h&gt; #include&lt;time.h&gt; #define Nor if(B[b].x&lt;5) B[b].x=5; ...

  • Diary

    在这里开个日记试一试,不知道能不能坚持。——2015年10月17日 2015/11/26 Thu【实验做了一年】 BUG PE和CL的连线接反了 使用00的信号存在延时和冒险(01→\to10) 放弃使用00信号,仅使用中间两个周期 CL2和CL3确实...

  • 【完结】囚生CYの备忘录(20221121-20230123)

    序言 上一篇写到字数上限,刚好这对我来说也是一个转折点,11月20日晚跑出场地万米42分整的历史第二好成绩,极大扭转了连日不振的状态,让我再次相信身体依然年轻,没有什么事情是办不到的。这两天早睡早起,控制...

  • 英语学习方法总结

    英语的逆向法就是先听录音,然后写出自己听到的句子,再学习其发音和读英语并进行背诵,最后对自己的学习进行归纳总结。这样就和传统学习英语的程序相反,所以称之为逆向法。 英语逆向法的优势 ①能迫使学习者...

  • [大话IT]圈套玄机—《圈子圈套》中的案例分析

    等到了明天早上,咱们就说都批准了,只是以后每年的服务费用不能打折,留这个便宜在咱们手里,陈总没办法,但一看总价和付款方式都依着他了,也只能同意,给自己一个台阶下了,咱们总算不白折腾这一下。”    托尼...

  • Freemarker 简介 及手册

    它是为Java程序员提供的一个开发包,或者说是一个类库。它不是面向最终用户的,而是为程序员提供的一款可以嵌入他们所开发产品的应用程序。 FreeMarker实际上是被设计用来生成HTML页面,尤其是通过

  • 2010爆牙笑话第一季!【转】

    结果没想到当晚巡逻车就看到N个穿着暴露、深夜还徘徊在校园阴暗处的女生,pol.ice叔叔费解地问其中一个为什么这么晚还不回去,只见那女生杏目圆睁,怒气冲冲地说道:“你管得着吗?考不上还不许被保送嘛!” 61.QQ上...

  • JavaEE知识体系

    在智联招聘上填写一个完整的简历还需要上传照片呢。 1.1.2 文件上传对页面的要求 1.必须使用表单,而不能是超链接; 2.表单的method必须是POST,而不能是GET; 3.表单的enctype必须是multipart/form-data; 4....

  • [转]告诉你真实的监狱生活

    今天看了篇文章,多震撼的,转来留个记号。  我不知道现在的社会变成了什么样子,因为我在监狱里待了整整5年。 我毕业于国内一所一流的大学,毕业后去国外镀过金,2000年以前我在一家证券公司工作。我曾有过很...

  • 吉隆坡兰卡威旅游信息整理

    你可以去瓜镇疯狂采购,你还可以,在这个又有田园气息又有现代风情的绝不会堵车且又风景一流的大岛上自驾游,你随时把车停下来看田园农耕,看沿海公路的波光潋滟,看不时守候在公路旁边的猴大王巴巴等着你的零食的...

  • Pink Floyd -《THE WALL》 分析文章 (作者 辛迪)

    有关 THE WALL 分析文章 ...专辑与电影讲述的是同一个故事:一个叫Pink Floyd的男孩,有年时二次大战夺去了他父亲的生命。他在母亲的过分呵护下长大,始终过着意气消沉的生活,最终开始吸毒,陷入疯狂状态。这张具有

  • sgu题目分类

    ... ...2.用extended_gcd找到一组(x0,y0...最后只要将这个子问题的解 * T 就可以了。 3.综上易知有解充要条件是:B被GCD[Ai | 0]整除 符号: 这里 GCD[A1, A2, ..., AN] = GCD[A1, GCD[A2, GCD[..., GCD...

Global site tag (gtag.js) - Google Analytics