如何優化程序性能

image

    這篇筆記主要是摘抄了具體的代碼示例,從代碼中體會如何優化程序的性能,《深刻理解計算機系統》已經看了近三分之二了,越看愈加現本身懂得太少太少了,正在題圖中的絕望之谷徘徊(我自認爲是這樣),至少比在愚昧山峯左邊的山腳徘徊要好不少。git

    咱們的編譯器已經提供了很好的優化機制,可是還有不少細節編譯器優化不到,或者說沒膽量去優化,由於有一些激進的優化頗有可能會違背程序員的初心。程序員

// 第一種
void twiddle1(long *xp, long *yp){
    *xp += *yp;
    *xp += *yp;
}

// 第二種
void twiddle2(long *xp, long *yp){
    *xp += 2* *yp;
}
複製代碼

    例如上面的程序,看到第一種寫法,咱們可能很容易的就想到第二種寫法,可是編譯器卻不會把它變成這種寫法。乍看它們沒什麼區別,咱們來分析一下內存引用。第一種須要 3 次內存引用,即讀\*xp、讀\*yp、寫\*xp;而第二種卻須要 6 次內存引用,即2 次讀\*xp、2 次讀\*yp、2 次寫\*xp。因此第一種的性能要比第二種好。github

    那編譯器看到第一種爲何就想不到第二種寫法呢?這不是很簡單的規則嗎?實際上上面的程序存在xp = yp的狀況,即兩個指針指向同一個內存位置。函數

// 第一種
*xp += *yp; // xp 處存放的值乘以 2
*xp += *yp; // xp 處存放的值乘以 2

// 第二種
*xp += 2* *yp; // xp 處存放的值乘以 3
複製代碼

    能夠看到,當它們都指向同一塊內存時,第一種寫法會讓原來的值增長 4 倍,而第二種寫法會讓原來的值增長 3 倍,產生了不一樣的效果,而編譯器會當這種狀況可能出現,因此編譯器並不會幫咱們優化第一種代碼,這須要程序員本身去維護。post

消除循環的低效率

    相信不少人都寫過下面相似的代碼,貌似沒有什麼能夠優化的,寫的挺好。性能

void lower1(char *s){
    long i;
    for(i = 0; i < strlen(s); i++){
        if(s[i] >= 'A' && s[i] <= 'Z'){
            s[i] -= ('A' - 'a');
        }
    }
}
複製代碼

    仔細看,會發現每次循環都會去調用strlen()函數,而這個函數明顯是要拖累性能的,實際上咱們只須要計算一次長度就能夠了,如今卻每次循環都須要去計算一次長度,因此能夠將計算移到前面只計算一次的地方。優化

void lower2(char *s){
    long i;
    long len = strlen(s);
    for(i = 0; i < len; i++){
        if(s[i] >= 'A' && s[i] <= 'Z'){
            s[i] -= ('A' - 'a');
        }
    }
}
複製代碼

    編譯器雖然會試着去進行代碼的移動,可是最終仍是沒有優化,是由於改變在哪裏調用函數或者調用多少次函數的變換,編譯器並不能比較可靠的發現一個函數是否有反作用,好比下面的狀況。ui

long f();

long func1(){
    return f() + f() + f() + f();
}

long func2(){
    return 4*f();
}
複製代碼

    這段代碼和開篇提到的代碼在形式上很像,可能你會說:它們不會指到同一塊內存了呀,編譯器這也不去優化嗎?考慮一下f()是下面的形式。spa

long count = 0;

long f(){
    return count++;
}
複製代碼

    是否是一下就發現問題了,func1()調用 4 次f(),而func2()只調用 1 次f(),它們最終的結果毫不是簡單的 4 倍關係。指針

編寫適合條件傳送實現的代碼

    若是編譯器可以產生使用條件數據傳送而不是條件控制轉移的代碼,那麼就能夠大大的提升程序的性能,關於條件數據傳送和條件控制轉移在舊文順序、條件、循環語句的底層解釋中描述的已經很明確了。好比下面的第一種寫法就比第二種要好。

// 第一種
void minmax1(long a[], long b[], long n){
    long i;
    for(i = 0; i < n; i++){
        if(a[i] > b[i]){
            long t = a[i];
            a[i] = b[i];
            b[i] = t;
        }
    }
}

// 第二種
void minmax2(long a[], long b[], long n){
    long i;
    for(i = 0; i < n; i++){
        long min = a[i] < b[i] ? a[i] : b[i];
        long max = a[i] < b[i] ? b[i] : a[i];
        a[i] = min;
        b[i] = max;
    }
}
複製代碼

    暫時就寫這幾個吧,還有個消除沒必要要的內存引用,由於它的性能問題不能從代碼中直接看出來,就不放出來了,工做中盡本身所能寫出優雅的代碼。

    題圖來自於一位不知名網友,侵權還請聯繫刪除。

相關文章
相關標籤/搜索