在很多程式設計的書籍中會給出這樣的建議:
在多重迴圈中,如果有可能,應當將最長的迴圈放在最內層,最短的迴圈放在最外層,以減少cpu 跨切迴圈層的次數。
這個「跨迴圈層」的概念本身是說,由外層迴圈進入內層迴圈是要重新初始化迴圈計數器的,包括儲存外層迴圈的計數器和載入內層迴圈計數器,退出內層的時候再恢復外層迴圈計數器。把長迴圈放在裡面可以顯著減小這些操作的數量。看下面兩個迴圈結構:
>>> 結構1
for(i=0; i < 100; i++)
for(j = 0; j < 20; j++)
sum += a[i][j];
>>> 結構2
for(j=0; j < 20; j++)
for(i=0; i < 100; i++)
sum+= a[i][j];
對於結構1來說,當cpu執行到內層迴圈的時候會執行sum += a[i][j]20次之後跳到外層迴圈去判斷一次,一共需要跳出去100次;對於結構2來說,當cpu執行到內層迴圈的時候會執行sum += a[i][j]100次才跳到外層,一共需要跳出去20次。很明顯對於結構1來說跳出的次數明顯大於結構2需要跳出的次數。這就是對於上面這個建議的理解。
但是,這種情況只是在這個二維陣列比較小的時候是有效的。另一方面還要注意資料結構本身的效率。這裡涉及到資料的cache命中的概念。如果你的「跳讀」會跨越cache交換塊,甚至page邊界的話,就會造成cpu資料cache重新批量裝載資料,甚至從虛擬記憶體中恢復磁碟資料,這當然嚴重影響效率。
陣列分配之後在記憶體中是線性存放的,是一整塊連續的空間,如果陣列的規模大到一定的程度,這個時候作業系統的cache在這個巨大的陣列面前顯得比較微小的時候就應該從另乙個角度去考慮調高效率,計算機中的cache是用來解決主存(也就是通常所說的記憶體)和cpu之間速率差異的機制,一般為sram,速度比主存快,造價比較高。一般情況下作業系統都有一些排程演算法去**cpu下一次所要使用的資料,從而提前把主存中的一部分資料取到cache中,當下次cpu要取的資料就在cache中的話就直接從cache中得到,提高系統效率,具體的cache置換演算法請參考網路。所以再看下面兩個例子:
>>> 結構3
for(i=0; i < 1000; i++)
for(j=0; j < 500; j++)
for(k=0; k < 100; k++)
sum += a[i][j][k];
>>> 結構4
for(k=0; k < 100; k++)
for(j=0; j < 500; j++)
for(i=0; i < 1000; i++)
sum += a[i][j][k];
從切換層數上計算的話,結構4好像要比結構3好很多,但是如果考慮上cpu置換cache所消耗的時間的話結構3要好於結構4,因為按照結構3的訪問順序,i是最不常變化的,j次之,k是最容易變化的,然而k和k+1在實際的記憶體中就是挨著的這大大增加了cache命中的機會;然而結構4中,i是最常變化的,而且i變化之後,i+1和i(k和j保持不變)的單元相差了500*100*sizeof(資料型別)個位元組,這使得cache命中率下降,因此需要做很多cache的置換工作,這部分時間如果加上的話,結構3比結構4就要好很多。
巢狀結構體案例
這個案例還是有很多地方可以學習的,決定記錄一下 參考 黑馬程式設計師匠心之作 c 教程從0到1入門程式設計 include include include include using namespace std 定義結構體 struct student struct teacher 賦值函式 voi...
多重 多層 巢狀迴圈
乙個迴圈結構中可以巢狀其他兩種迴圈結構,巢狀多少層和多少個都可以,一般不會超過兩層!所以多重迴圈又往往被稱為叫雙重迴圈。外層迴圈執行一次,內層迴圈執行一遍 輪。while dowhile 如果在列印圖形的時候,先看有幾行,外層迴圈控制列印幾行。再看有幾列,內層迴圈控制每列列印的內容。一會break和...
結構體巢狀結構體名
結構體巢狀結構體名 前一段時間在看ddk中例子的時候,看到這樣的的結構體定義 typedef struct common device data common device data,pcommon device data typedef struct pdo device data pdo dev...