如何最佳化程式的效能
這篇筆記主要是摘抄了具體的程式碼示例,從程式碼中體會如何最佳化程式的效能,《深入理解計算機系統》已經看了近三分之二了,越看越發現自己懂得太少太少了,正在題圖中的絕望之谷徘徊(我自認為是這樣),至少比在愚昧山峰左邊的山腳徘徊要好很多。
我們的編譯器已經提供了很好的最佳化機制,但是還有很多細節編譯器最佳化不到,或者說沒膽量去最佳化,因為有一些激進的最佳化很有可能會違背程式設計師的初心。
// 第一種
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
。所以第一種的效能要比第二種好。
那編譯器看到第一種為什麼就想不到第二種寫法呢?這不是很簡單的規則嗎?實際上上面的程式存在xp = yp
的情況,即兩個指標指向同一個記憶體位置。
// 第一種
*xp += *yp; // xp 處存放的值乘以 2
*xp += *yp; // xp 處存放的值乘以 2
// 第二種
*xp += 2* *yp; // xp 處存放的值乘以 3
可以看到,當它們都指向同一塊記憶體時,第一種寫法會讓原來的值增加 4 倍,而第二種寫法會讓原來的值增加 3 倍,產生了不同的效果,而編譯器會當這種情況可能出現,所以編譯器並不會幫我們最佳化第一種程式碼,這需要程式設計師自己去維護。
消除迴圈的低效率
相信很多人都寫過下面類似的程式碼,貌似沒有什麼可以最佳化的,寫的挺好。
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');
}
}
}
編譯器雖然會試著去進行程式碼的移動,但是最終還是沒有最佳化,是因為改變在哪裡呼叫函式或者呼叫多少次函式的變換,編譯器並不能比較可靠的發現一個函式是否有副作用,比如下面的情況。
long f();
long func1(){
return f() + f() + f() + f();
}
long func2(){
return 4*f();
}
這段程式碼和開篇提到的程式碼在形式上很像,可能你會說:它們不會指到同一塊記憶體了呀,編譯器這也不去最佳化嗎?考慮一下f()
是下面的形式。
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;
}
}
暫時就寫這幾個吧,還有個消除不必要的記憶體引用
,因為它的效能問題不能從程式碼中直接看出來,就不放出來了,工作中儘自己所能寫出優雅的程式碼。
題圖來自於一位不知名網友,侵權請聯絡刪除。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31555494/viewspace-2284400/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 效能最佳化 = 改改程式碼?
- 如何提高python程式的效能Python
- 如何分析並最佳化網頁效能?網頁
- CSAPP 第五章 最佳化程式效能APP
- 程式設計技巧整理:Java程式效能最佳化總結!程式設計Java
- 常用的效能最佳化方法
- 報表的效能最佳化
- 這6種效能最佳化,讓你的程式飛起來!
- 小程式首屏載入過慢的效能最佳化策略
- Node效能如何進行監控以及最佳化?
- 如何優化程式效能優化
- 達達快送小程式效能最佳化實踐
- 好程式設計師分享Web前端效能最佳化程式設計師Web前端
- Unity效能最佳化CPU最佳化Unity
- Redis效能最佳化的18招Redis
- 基於Python的效能最佳化Python
- MethodImpl最佳化效能
- HarmonyOS 效能最佳化
- JavaScript效能最佳化JavaScript
- oracle 效能最佳化Oracle
- 前端效能最佳化前端
- 如何最佳化大模型在Java環境下的效能表現大模型Java
- 效能最佳化指南:效能最佳化的一般性原則與方法
- 前端效能最佳化——圖片最佳化前端
- Unity效能最佳化GPU渲染最佳化UnityGPU
- web前端效能最佳化——圖片載入的最佳化Web前端
- 如何最佳化 RAG 系統的效能表現?10 條實用策略
- MySQL & MariaDB效能最佳化 大牛的blogMySql
- 架構視角的效能最佳化架構
- iOS-效能最佳化的那些事iOS
- 頂級大廠Quora如何最佳化資料庫效能?資料庫
- Redis效能瓶頸揭秘:如何最佳化大key問題?Redis
- Mysql效能最佳化(三)MySql
- 網站效能最佳化網站
- Web 效能最佳化方法Web
- 如何使用 Set 來提高程式碼的效能
- 好程式設計師Java培訓分享-簡單的效能最佳化技巧程式設計師Java
- WPF 效能最佳化-列表控制元件效能控制元件