1. 程式人生 > >深入理解計算機系統筆記一

深入理解計算機系統筆記一

   我看的是《深入理解計算機系統》原書第三版,這真的是一本相見恨晚的好書。看了幾天,有些內容已經在實際程式設計中獲益了。我重點關注的是優化程式效能。作為程式設計師,我們無須為了寫出高效程式碼而去了解一些編譯器的內部工作。但是,為了在C程式中作出好的編碼選擇,我們確實需要了解一些機器程式碼以及編譯器將不同的C語句轉化為機器程式碼的方式。比如一個switch語句是否總是比一系列的if-else語句高效得多while迴圈比for迴圈更有效嗎指標引用比陣列索引更有效嗎?(從目前我個人的經驗來看,確實要更有效,週六剛測試的程式碼,比較簡單的程式碼,大概快了10ms,目前我心中對這個原因還是有一定的想法,但還不確定,至少指標的++的操作要比通過索引定址的方式直覺上看來要簡單,近水樓臺先得月)。為什麼將迴圈求和的結果放到一個本地變數中,會比將其放到一個通過引用傳遞過來的引數中,執行起來快很多呢

?(因為減少了對儲存器的訪問?)為什麼我們只是簡單地重新排列一下算術表示式中的括號就能讓函式執行的更快?(在書中稱為重新結合變換,因為括號改變了向量元素之間的合併順序,比如 acc = (acc op data[i]) op data[i+1]; 重新排列後, acc = acc op (data[i] op data[i+1]);後面的這種方式增加了可以並行執行的運算元量。

   最讓我印象深刻的是關於編譯器對程式的安全優化,也就是說對於程式可能遇到的所有可能的情況,在C語音標準提供的保證之下,優化後得到的程式和未優化後的版本有一樣的行為,限制編譯器只進行安全的優化。為了理解決定一種程式轉換是否安全的難度,讓我們來看看下面的這兩個過程

void twiddle1(long *xp, long *yp)
{
    *xp += *yp;
    *xp += *yp;
}

void twiddle2(long *xp, long *yp)
{
    *xp += 2* *yp;
}

   乍一看,這兩個過程似乎有相同的行為。他們都是講儲存在指標yp指示的位置處的值兩次加到指標xp指示的位置處的值。另一方面,函式twiddle2效率更高一些。它只要求3次記憶體引用(讀*xp,讀*yp,寫*xp),而前者需要6次。因此,如果要編譯器編譯過程twiddle1,我們會認為twiddle2執行的計算能產生更有效的程式碼。

    不過,考慮xp指標等於yp的情況。此時函式twiddle1會執行,下面的程式碼段,結果xp的值為原來的4倍。

*xp += *xp;
*xp += *xp;

   而函式twiddle會執行下面的計算

*xp += 2* *xp;

結果是xp的值等於原來的3倍。通過這一個例子,我是跪服了搞編譯器優化的大神。