日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

无止境的内存优化——停不下的循环

發布時間:2025/3/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 无止境的内存优化——停不下的循环 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

小伙伴們是不是跟我一樣,以為之前的內存優化已經完成了?不,這才剛剛開始……讓我們一起進入這無休止的循環吧!

switch語句和查找表 / Switch statement vs. lookup tables

switch語句通常用于以下情況:

調用幾個函數中的一個

設置一個變量或返回值

執行幾個代碼片斷中的一個

如果case表示是密集的,在使用switch語句的前兩種情況中,可以使用效率更高的查找表。比如下面的兩個實現匯編代碼轉換成字符串的例程:

char * Condition_String1(int condition) {switch(condition) {case 0: return "EQ";case 1: return "NE";case 2: return "CS";case 3: return "CC";case 4: return "MI";case 5: return "PL";case 6: return "VS";case 7: return "VC";case 8: return "HI";case 9: return "LS";case 10: return "GE";case 11: return "LT";case 12: return "GT";case 13: return "LE";case 14: return "";default: return 0;} } char * Condition_String2(int condition) {if((unsigned) condition >= 15) return 0;return"EQ\0NE\0CS\0CC\0MI\0PL\0VS\0VC\0HI\0LS\0GE\0LT\0GT\0LE\0\0" +3 * condition; }

第一個例程需要240個字節,第二個只需要72個。

循環終止 / Loop termination

如果不加留意地編寫循環終止條件,就可能會給程序帶來明顯的負擔。我們應該盡量使用“倒數到零”的循環,使用簡單的循環終止條件。循環終止條件相對簡單,程序在執行的時候也會消耗相對少的時間。拿下面兩個計算n!的例子來說,第一個例子使用遞增循環,第二個使用遞減循環。

int fact1_func (int n) {int i, fact = 1;for (i = 1; i <= n; i++)fact *= i;return (fact); } int fact2_func(int n) {int i, fact = 1;for (i = n; i != 0; i--)fact *= i;return (fact); }

結果是,第二個例子要比第一個快得多。

更快的for()循環 / Faster for() loops

這是一個簡單而有效的概念,通常情況下,我們習慣把for循環寫成這樣:

for( i = 0; i < 10; i++){ ... }

i 值依次為:0,1,2,3,4,5,6,7,8,9

在不在乎循環計數器順序的情況下,我們可以這樣:

for( i = 10; i--; ) { ... }

i 值依次為: 9,8,7,6,5,4,3,2,1,0,而且循環要更快

這種方法是可行的,因為它是用更快的i--作為測試條件的,也就是說“i是否為非零數,如果是減一,然后繼續”。相對于原先的代碼,處理器不得不“把i減去10,結果是否為非零數,如果是,增加i,然后繼續”,在緊密循環(tight loop)中,這會產生顯著的區別。

這種語法看起來有一點陌生,卻完全合法。循環中的第三條語句是可選的(無限循環可以寫成這樣for(;;)),下面的寫法也可以取得同樣的效果:

for(i = 10; i; i--){}

或者:

for(i = 10; i != 0; i--){}

我們唯一要小心的地方是要記住循環需要停止在0(如果循環是從50-80,這樣做就不行了),而且循環的計數器為倒計數方式。

另外,我們還可以把計數器分配到寄存器上,可以產生更為有效的代碼。這種將循環計數器初始化成循環次數,然后遞減到零的方法,同樣適用于while和do語句。

混合循環/ Loop jamming 在可以使用一個循環的場合,決不要使用兩個。但是如果你要在循環中進行大量的工作,超過處理器的指令緩沖區,在這種情況下,使用兩個分開的循環可能會更快,因為有可能這兩個循環都被完整的保存在指令緩沖區里了。

// 原先的代碼 for(i = 0; i < 100; i++){stuff(); } for(i = 0; i < 100; i++){morestuff(); } //更好的做法 for(i = 0; i < 100; i++){stuff();morestuff(); }

函數循環 / Function Looping

調用函數的時候,在性能上就會付出一定的代價。不光要改變程序指針,還要將那些正在使用的變量壓入堆棧,分配新的變量空間。為了提高程序的效率,在程序的函數結構上,有很多工作可以做。保證程序的可讀性的同時,還要盡量控制程序的大小。

如果一個函數在一個循環中被頻繁調用,就可以考慮將這個循環放在函數的里面,這樣可以免去重復調用函數的負擔,比如:

for(i = 0 ; i < 100 ; i++) { func(t,i); } void func(int w, d) { lots of stuff. }

可以寫成:

func(t); void func(w) { for(i = 0; i < 100; i++) { //lots of stuff. } }

展開循環 / Loop unrolling

為了提高效率,可以將小的循環解開,不過這樣會增加代碼的尺寸。循環被拆開后,會降低循環計數器更新的次數,減少所執行的循環的分支數目。如果循環只重復幾次,那它完全可以被拆解開,這樣,由循環所帶來的額外開銷就會消失。

比如:

for(i = 0; i < 3; i++){ something(i); } //更高效的方式: something(0); something(1); something(2);

因為在每次的循環中,i 的值都會增加,然后檢查是否有效。編譯器經常會把這種簡單的循環解開,前提是這些循環的次數是固定的。對于這樣的循環:

for(i = 0; i < limit; i++) { ... }

就不可能被拆解,因為我們不知道它循環的次數到底是多少。不過,將這種類型的循環拆解開并不是不可能的。

與簡單循環相比,下面的代碼的長度要長很多,然而具有高得多的效率。選擇8作為分塊大小,只是用來演示,任何合適的長度都是可行的。例子中,循環的成立條件每八次才被檢驗一次,而不是每次都要檢驗。如果需要處理的數組的大小是確定的,我們就可以使用數組的大小作為分塊的大小(或者是能夠整除數組長度的數值)。不過,分塊的大小跟系統的緩存大小有關。

#include<stdio.H> #define BLOCKSIZE (8) int main(void) { int i = 0; int limit = 33; /* could be anything */ int blocklimit;/* The limit may not be divisible by BLOCKSIZE, go as near as we can first, then tidy up.*/ blocklimit = (limit / BLOCKSIZE) * BLOCKSIZE;/* unroll the loop in blocks of 8 */ while(i < blocklimit) { printf("process(%d)\n", i); printf("process(%d)\n", i+1); printf("process(%d)\n", i+2); printf("process(%d)\n", i+3); printf("process(%d)\n", i+4); printf("process(%d)\n", i+5); printf("process(%d)\n", i+6); printf("process(%d)\n", i+7); /* update the counter */ i += 8; } /* * There may be some left to do.* This could be done as a simple for() loop, * but a switch is faster (and more interesting) */ if( i < limit ) { /* Jump into the case at the place that will allow* us to finish off the appropriate number of items. */ switch( limit - i ) { case 7 : printf("process(%d)\n", i); i++; case 6 : printf("process(%d)\n", i); i++; case 5 : printf("process(%d)\n", i); i++; case 4 : printf("process(%d)\n", i); i++; case 3 : printf("process(%d)\n", i); i++; case 2 : printf("process(%d)\n", i); i++; case 1 : printf("process(%d)\n", i); }} return 0; }

經過惰性評估和二分分解煎熬,小編以為自己已經逃出生天了,哪知這才剛剛開始,小伙伴們,還請持續關注更新,更多干貨和資料請直接聯系我,也可以加群710520381,邀請碼:柳貓,歡迎大家共同討論

轉載于:https://my.oschina.net/u/3875054/blog/1828206

總結

以上是生活随笔為你收集整理的无止境的内存优化——停不下的循环的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。