自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

陳皓:代碼執(zhí)行的效率

開發(fā) 開發(fā)工具
在《性能調(diào)優(yōu)攻略》里,我說過,要調(diào)優(yōu)性需要找到程序中的Hotspot,也就是被調(diào)用最多的地方,這種地方,只要你能優(yōu)化一點點,你的性能就會有質(zhì)的提高。在這里我給大家舉三個關(guān)于代碼執(zhí)行效率的例子……

在《性能調(diào)優(yōu)攻略》里,我說過,要調(diào)優(yōu)性需要找到程序中的Hotspot,也就是被調(diào)用最多的地方,這種地方,只要你能優(yōu)化一點點,你的性能就會有質(zhì)的提高。在這里我給大家舉三個關(guān)于代碼執(zhí)行效率的例子(它們都來自于網(wǎng)上)

第一個例子

PHP中Getter和Setter的效率來源reddit

這個例子比較簡單,你可以跳過。

考慮下面的PHP代碼:我們可看到,使用Getter/Setter的方式,性能要比直接讀寫成員變量要差一倍以上。

  1. <?php  
  2.     //dog_naive.php  
  3.    
  4.     class dog {  
  5.         public $name = "";  
  6.         public function setName($name) {  
  7.             $this-&gt;name = $name;  
  8.         }  
  9.         public function getName() {  
  10.             return $this-&gt;name;  
  11.         }  
  12.     }  
  13.    
  14.     $rover = new dog();  
  15.         //通過Getter/Setter方式  
  16.     for ($x=0; $x<10; $x++) {  
  17.         $t = microtime(true);  
  18.         for ($i=0; $i<1000000; $i++) {  
  19.             $rover->setName("rover");  
  20.             $n = $rover->getName();  
  21.         }  
  22.         echo microtime(true) - $t;  
  23.         echo "\n";  
  24.     }  
  25.         //直接存取變量方式  
  26.         for ($x=0; $x<10; $x++) {  
  27.         $t = microtime(true);  
  28.         for($i=0; $i<1000000; $i++) {  
  29.             $rover->name = "rover";  
  30.             $n = $rover->name;  
  31.         }  
  32.         echo microtime(true) - $t;  
  33.         echo "\n";  
  34.     }  
  35. ?> 

這個并沒有什么稀,因為有函數(shù)調(diào)用的開銷,函數(shù)調(diào)用需要壓棧出棧,需要傳值,有時還要需要中斷,要干的事太多了。所以,代碼多了,效率自然就慢了。所有的語言都這個德行,這就是為什么C++要引入inline的原因。而且Java在打開優(yōu)化的時候也可以優(yōu)化之。但是對于動態(tài)語言來說,這個事就變得有點困難了。

你可能會以為使用下面的代碼(Magic Function)會好一些,但實際其性能更差。

  1. class dog {  
  2.     private $_name = "";  
  3.     function __set($property,$value) {  
  4.         if($property == 'name'$this->_name = $value;  
  5.     }  
  6.     function __get($property) {  
  7.         if($property == 'name'return $this->_name;  
  8.     }  

動態(tài)語言的效率從來都是一個問題,如果你需要PHP有更好的性能,你可能需要使用FaceBook的HipHop來把PHP編譯成C語言。

第二個例子

為什么Python程序在函數(shù)內(nèi)執(zhí)行得更快?來源StackOverflow

考慮下面的代碼,一個在函數(shù)體內(nèi),一個是全局的代碼。

函數(shù)內(nèi)的代碼執(zhí)行效率為 1.8s

  1. def main():  
  2.     for i in xrange(10**8):  
  3.         pass  
  4. main() 

函數(shù)體外的代碼執(zhí)行效率為 4.5s

  1. for i in xrange(10**8):  
  2.     pass 

不用太糾結(jié)時間,只是一個示例,我們可以看到效率查得很多。為什么會這樣呢?我們使用 dis module 反匯編函數(shù)體內(nèi)的bytecode 代碼,使用 compile builtin 反匯編全局bytecode,我們可以看到下面的反匯編(注意我高亮的地方)

Main函數(shù)反匯編

  1. 13 FOR_ITER                 6 (to 22)  
  2. 16 STORE_FAST               1 (i)  
  3. 19 JUMP_ABSOLUTE           13 

全局代碼

  1. 13 FOR_ITER                 6 (to 22)  
  2. 16 STORE_NAME               1 (i)  
  3. 19 JUMP_ABSOLUTE           13 

我們可以看到,差別就是 STORE_FAST 和 STORE_NAME,前者比后者快很多。所以,在全局代碼中,變量i成了一個全局變量,而函數(shù)中的i是放在本地變量表中,所以在全局變量表中查找變量就慢很多。如果你在main函數(shù)中聲明global i 那么效率也就下來了。原因是,本地變量是存在一個數(shù)組中(直到),用一個整型常量去訪問,而全局變量存在一個dictionary中,查詢很慢。

(注:在C/C++中,這個不是一個問題)

第三個例子

為什么排好序的數(shù)據(jù)在遍歷時會更快?來源StackOverflow

參看如下C/C++的代碼:

  1. for (unsigned i = 0; i < 100000; ++i) {  
  2.    // primary loop  
  3.     for (unsigned j = 0; j < arraySize; ++j) {  
  4.         if (data[j] >= 128)  
  5.             sum += data[j];  
  6.     }  

如果你的data數(shù)組是排好序的,那么性能是1.93s,如果沒有排序,性能為11.54秒。差5倍多。無論是C/C++/Java,或是別的什么語言都基本上一樣。

這個問題的原因是—— branch prediction (分支預(yù)判)偉大的stackoverflow給了一個非常不錯的解釋。

考慮我們一個鐵路分叉,當(dāng)我們的列車來的時候, 扳道員知道分個分叉通往哪,但不知道這個列車要去哪兒,司機知道要去哪,但是不知道走哪條分叉。所以,我們需要讓列車停下來,然后司機和扳道員溝通一下。這樣的性能太差了。

所以,我們可以優(yōu)化一下,那就是猜,我們至少有50%的概率猜對,如果猜對了,火車行駛性能巨高,猜錯了,就得讓火車退回來。如果我猜對的概率高,那么,我們的性能就會高,否則老是猜錯了,性能就很差。

[[84577]]

Image by Mecanismo, from Wikimedia Commons:http://commons.wikimedia.org/wiki/File:Entroncamento_do_Transpraia.JPG

我們的if-else 就像這個鐵路分叉一樣,下面紅箭頭所指的就是搬道器。

那么,我們的搬道器是怎么預(yù)判的呢?就是使用過去的歷史數(shù)據(jù),如果歷史數(shù)據(jù)有90%以上的走左邊,那么就走左邊。所以,我們排好序的數(shù)據(jù)就更容易猜得對。

排好序的

  1. T = 走分支(條件表達式為true)  
  2. N = 不走分支(條件表達式為false)  
  3.    
  4. data[] = 0, 1, 2, 3, 4, ... 126, 127, 128, 129, 130, ... 250, 251, 252, ...  
  5. branch = N  N  N  N  N  ...   N    N    T    T    T  ...   T    T    T  ...  
  6.    
  7. = NNNNNNNNNNNN ... NNNNNNNTTTTTTTTT ... TTTTTTTTTT  (easy to predict) 

未排序的

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

從上面我們可以看到,排好序的數(shù)據(jù)更容易預(yù)測分支。

對此,那我們怎么辦?我們需要在這種循環(huán)中除去if-else語句。比如:

我們把條件語句:

  1. if (data[j] >= 128)  
  2. sum += data[j]; 

變成:

  1. int t = (data[j] - 128) >> 31;  
  2. sum += ~t & data[j]; 

“沒有分叉”的性能基本上和“排好序有分支”一個樣,無論是C/C++,還是Java。

注:在GCC下,如果你使用 -O3 or -ftree-vectorize 編譯參數(shù),GCC會幫你優(yōu)化分叉語句為無分叉語句。VC++2010沒有這個功能。

最后,推薦大家一個網(wǎng)站——Google Speed,網(wǎng)站上的有一些教程告訴你如何寫出更快的Web程序

(全文完)

原文鏈接:http://coolshell.cn/articles/7886.html

責(zé)任編輯:林師授 來源: 酷殼
相關(guān)推薦

2014-06-12 08:53:01

團隊團隊效率

2013-07-25 10:28:46

加班工作效率職場

2012-06-21 09:43:45

2012-02-02 10:35:12

C++

2014-02-24 10:45:00

2012-07-25 10:16:59

2012-04-27 10:24:07

2012-09-03 13:51:43

測試軟件測試單元測試

2012-08-02 09:36:58

fork面試題

2014-04-15 10:13:01

2021-12-22 10:49:42

架構(gòu)運維技術(shù)

2012-10-15 16:13:29

2012年度IT博客大陳皓

2012-01-16 09:58:26

2012-08-16 13:31:06

陳皓架構(gòu)師

2014-07-29 11:35:34

2014-08-20 16:37:51

2012-10-25 17:56:43

陳皓云計算架構(gòu)師大會

2012-10-25 16:07:33

云計算架構(gòu)師

2013-04-02 10:10:06

JavaScriptJS

2021-02-20 08:05:35

代碼效率C++
點贊
收藏

51CTO技術(shù)棧公眾號