《代碼大全2》學習筆記4

來源:互聯網
上載者:User

標籤:程式員   編譯器   作業系統   

第五部分:代碼改善

25 代碼調整策略

70年代,程式員意識到過分專註效能會損失程式的可讀性和可維護性。

對普通使用者來說,程式員按時交付軟體、一個清爽的介面、避免死機,常常比效能更重要。

最佳化效率前先考慮幾個問題:

1、程式需求(客戶的需求要求太高,其實根本沒有必要這麼高)

2、程式的設計(當前的設計很難做良好的最佳化工作)

3、具體設計(比如採用快速排序還是冒泡排序)

4、同作業系統的互動(影響你的效率,有時候你自己也沒有意思到有系統調用,比如編譯器會產生系統調用,或者某個庫使用了)

5、代碼編譯(好的編譯器都會替你最佳化)

6、硬體

7、代碼調整(本章主題,細節代碼)

“不足4%的部分常常佔用了超過50%的已耗用時間”

 

1、“程式碼數多,並不代表運行速度慢”

for(int i=0;i<10;i++)
 a[i]=i;

與
a[0]=1;a[2]=2;……a[9]=9;

相比,明顯是後面一個更快。

2、“最佳化要考慮可移植性,可能一種方法放到另外一種語言,甚至同一語言的另外一種編譯器,都可能產生反作用。”

3、“很難找到那4%的部分,程式員做的最佳化往往帶來的效果都微不足道。”

4、“對那4%的最佳化,可能顧此失彼,反而導致整體效能的下降。”

5、“速度的最佳化會帶來可讀性、封裝性、正確性的破壞,帶來的好處並不值得。”

6、“運行速度的要求現在越來越低與正確性等方面。”

7、“程式員應該使用高品質的設計,把代碼寫正確,使之模組化並易於修改,將讓後期的維護工作變得很容易。”

8、“編譯器最佳化開啟會提供效能”
c++編譯器開啟最佳化基本會提高大約50%的效能。可以參考這個例子:
http://topic.csdn.net/u/20091113/14/9d793a37-9953-43be-940f-26e4b64d8a6b.html
最佳化的很激進。

9、“系統影響”
(1)訪問記憶體比訪問網路和磁碟快的百倍。
(2)系統調用
(3)記憶體資料分配不當,導致記憶體分頁也會影響效能:
for(int column=0;column<100;column++)
 for(int row=0;row<1000000;row++)
  table[row][column] = new XXX;
因為一般讀取資料,都是讀一行,然後取每一列,這種分配方案會導致在讀取時都會切換記憶體頁(缺頁中斷),影響效能。
所以應該是:
for(int row=0;row<1000000;row++)
 for(int column=0;column<100;column++)
  table[row][column] = new XXX;
不過這樣會導致局部運行變慢,具體見下章。

10、c++函數的參數越多,調用速度越慢。【應該都是說基礎資料型別 (Elementary Data Type),不知道結構體怎麼樣】
很神奇java的函數參數數量不影響運行速度,應該都是做了最佳化的。
多態函數調用速度最慢。
11、沒必要把數組的移動變成多維指標來操作,因為編譯器基本都替我們最佳化了,如果我們再做,會導致可讀性下降。

 

26 代碼調整技術

“減少佔用資源主要是通過調整類和資料結構,而非代碼調整。”

1、case語句、if=else先判斷常見的。

2、用查表法代替複雜邏輯。

3、算出的結構可以放在緩衝中下次用。

4、把迴圈中的判斷外提
for(int i=0;i<count;i++)
{
 if(type=A)
   xxxx
 else
  xxx
}
變成
if(type=A)
 for(int i=0;i<count;i++)
  xxx
else
 for(int i=0;i<count;i++)
  xxx
但是這樣就出現了重複代碼,對維護代碼是個問題。

5、展開
for(int i=0;i<count-2;i++)
 a[i]=i;
變成
for(int i=0;i<count;i++)
{
 a[i]=i;
 a[i]=++i;
 a[i]=++i;
}
xxxx//處理額外資料
基本可以當成是不良編程,不過如果是很簡單的處理,可以提供34%的效率。
【感覺意義不大,如果是迴圈內部處理很耗時的話,這種提高就被沖淡了】

6、減少迴圈內部的處理
for(int i=0;i<count;i++)
 a[i]=b[i]*p->p->p;
變成
pr=p->p->p;
for(int i=0;i<count;i++)
 a[i]=b[i]*pr;
7、哨兵值【這個感覺比較變態,第一次見這麼詭異的方法】
for(int i=0;i<count;i++)
 if(item[i]==type)
 {bFind=true;break;}
改成
item[count]=type;
while(item[i]!=type)
 i++;
if(i<count)
xxxx
太詭異了,等於少了一個判斷條件
8、把最忙的迴圈放在內層
觀察上章9,如果不考慮分配記憶體,那麼第一個的迴圈總算是1000000*101次,而第二個是1000001*100,少了999900次迴圈。
但是雖然局部最佳化了,整體下降了。
如果不是分配記憶體而是簡單處理,倒是不錯的。

9、用加法替代乘法

10、迴圈下標不用浮點型而用整型【效率提高3.5倍,不過正常人應該都不會用浮點型做迴圈迴圈下標吧】

11、用一維數組代替多維陣列,沒有什麼效率提高,編譯器已經最佳化了。

12、把常用計算結果變成常量。
比如int log2(int x){return log(x)/log(2);}
把log(2)變成常量使用。

13、小心系統函數
對於不需要精度的函數,直接自己寫。

14、使用正確的常量類型
當賦值變數時,給於的值需要轉換,那麼會消耗時間,因為要做強制轉換。【有空編碼試試】

15、預先算出結果,直接查表

16、把子程式變成內嵌函式

17、用低級語言重寫代碼【改成彙編難度挺大的,尤其是比較複雜的程式,用彙編重寫太難了- - 估計寫幾個演算法還可以,不過不清楚怎麼調用彙編的程式,難道當成是一個獨立程式調用返回結果嗎?還是編譯器可以把彙編出來的東西當做程式一部分調用?tc有個small模式可以調用彙編代碼.ASM檔案】
有空試試這樣編碼
http://zhidao.baidu.com/question/31397560.html

試了下linux版的卡死不動了,什麼都沒列印出來。

linux上面的彙編蠻難理解的,跟以前上學學的都不一樣。

g++ -S可以產生彙編代碼。

拼字上多了一些字元。一些指令後面多了個L,源運算元與目的運算元位置對調了,常數前面加了$,寄存器前面加了%

http://tieba.baidu.com/f?kz=310375556

http://wenku.baidu.com/view/e8752e7f5acfa1c7aa00cc39.html

有空可以看看。

也了一個簡單的例子:
int a = 1;
int b = 2;

int main()
{
__asm__
(
  "movl a,%ecx \n"
 "xchg b,%ecx \n"
 "movl %ecx,a \n"
 );
return 0;
}

變數必須用全部定義,用static都不行。

不過一般現在在代碼裡面內嵌彙編意義不大,看這篇
http://topic.csdn.net/u/20100413/20/87aa7378-cd9f-44ad-90ae-4201a3680b71.html


本文出自 “飛翔正義的部落格” 部落格,請務必保留此出處http://xzq2000.blog.51cto.com/2487359/1767393

《代碼大全2》學習筆記4

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.