區域性性原理: cpu訪問儲存器時,無論是訪問指令還是訪問資料,所訪問的儲存單元都趨於聚集在乙個較小的連續區域中。
計算機儲存結構記憶體,一級快取,二級快取,暫存器等。快取是用來存放從記憶體中取出的指令和資料,用來提高cpu訪問記憶體的速度而暫存器是用來存放cpu在執行指令時所需要的運算元或執行結果暫存器的內容可以通過程式設計控制,也就是說對程式設計師而言是可見的,而快取不能通過程式設計控制,對程式設計師而言是透明的。快取的訪問速度是遠遠快於記憶體的,計算機執行運算時總是把用到記憶體的相關的資料放到快取中以便於下次用到時直接讀取快取資料,快取只能存放小部分資料,而且快取的資料也不可能百分百命中,如果快取不命中,那麼cpu 只能從記憶體再次讀取資料。所以提高程式的區域性性,對於加快程式的執行速度有幫助的。
二位陣列在記憶體中是以線性存放,以下就是int[5,4] myarray的陣列內容如下
0, 0, 0 ,0
1, 1,1 , 1
2,2, 2, 2
3, 3, 3, 3
4, 4, 4, 4
它在記憶體中是以以下方式存放的:
0, 0, 0 ,0 1, 1,1 , 1 ,2,2, 2, 2 ,3, 3, 3, 3 ,4, 4, 4, 4
如果計算陣列myarray所有元素之和,有兩種方式:
1 按行依次訪問myarray 陣列元素,並依次求和
2 按列依次訪問myarray陣列元素,並依次求個
這兩種方式在效能上有區別嗎?為什麼
答案:有區別,按行訪問陣列元素求和總是快於按列訪問陣列元素的求和。
請看如下**:
usingsystem;
using
system.collections.generic;
using
system.linq;
using
system.text;
using
system.diagnostics;
using
system.threading;
namespace
hbb0b0.dotnettrace
",datetime.now);
trace.writeline(content);
watch.start();
numbertest numbertest = new
numbertest();
for (int i = 0; i < 5;i++)
watch.stop();
//統計總的**的執行時間
content = string.format("
main cost:
", watch.elapsedmilliseconds);
trace.writeline(content);
console.read();}}
class
numbertest
getupperbound(0): getupperbound(1):
", datetime.now.tostring(), m_intarray.getupperbound(0), m_intarray.getupperbound(1
)); trace.writeline(content);
trace.writeline(
"init data");
for (int i = 0; i <= m_intarray.getupperbound(0); i++)}}
//////
按行優先方式求和陣列
/// public
void
calcbyrowfirst()
}watch.stop();
//統計**的執行時間
string content = string.format("
calcbyrowfirst:cost: result:
", watch.elapsedmilliseconds, result);
trace.writeline(content);
} //////
按列優先方式求和陣列
/// public
void
calcbycolumnfirst()
}watch.stop();
//統計**的執行時間
string content = string.format("
calcbycolumnfirst:cost: result:
", watch.elapsedmilliseconds, result);
trace.writeline(content);}}
}
<?xml version="1.0" encoding="utf-8" ?>
輸出結果如下:
main: at:2013/2/20 11:06:01
numbertest time:2013/2/20 11:06:01 getupperbound(0):8999 getupperbound(1):8999
init data
calcbyrowfirst:cost:3991result:728676044998
calcbycolumnfirst:cost:8264result:728676044998
calcbyrowfirst:cost:4816result:728676044998
calcbycolumnfirst:cost:6969result:728676044998
calcbyrowfirst:cost:4952result:728676044998
calcbycolumnfirst:cost:8203result:728676044998
calcbyrowfirst:cost:5006 result:728676044998
calcbycolumnfirst:cost:7134 result:728676044998
calcbyrowfirst:cost:4127 result:728676044998
calcbycolumnfirst:cost:6388 result:728676044998
main cost:62952
main: at:2013/2/20 11:09:51
numbertest time:2013/2/20 11:09:51 getupperbound(0):8999 getupperbound(1):8999
init data
calcbyrowfirst:cost:4939 result:728676044998
calcbycolumnfirst:cost:7807 result:728676044998
calcbyrowfirst:cost:4956 result:728676044998
calcbycolumnfirst:cost:8167 result:728676044998
calcbyrowfirst:cost:4894 result:728676044998
calcbycolumnfirst:cost:7592 result:728676044998
calcbyrowfirst:cost:3833 result:728676044998
calcbycolumnfirst:cost:7082 result:728676044998
calcbyrowfirst:cost:4121 result:728676044998
calcbycolumnfirst:cost:8109 result:728676044998
main cost:66289
經過多次比對,按行訪問陣列元素求和總是快於按列訪問陣列元素的求和。
造成這種情況的原因就是cpu 區域性性原理。
cpu在訪問陣列元素的時候,總會把他相鄰的元素讀取出來並放入到快取中。假設一次訪問記憶體中的陣列元素,它會把後續的99個元素放到快取中,那麼cpu每讀取
一次記憶體就可以減少後續的99次讀取記憶體。
按行訪問的記憶體讀取次數就是
900*900
而按列訪問記憶體的讀取次數就是
9000*9000
按列訪問同樣會讀取乙個陣列元素後快取後續的99個陣列元素,但是按列求和陣列用到的資料並不是快取的的99個元素,雖然快取了99個元素,但是後續的99次操作一次快取
也不會命中,所以按列訪問陣列元素求和是會訪問記憶體9000*9000。
所以輸出結果中行讀取比列讀取快也是自然而然的事情。
區域性性原理
區域性性原理 cpu訪問 儲存器時,無論是訪問指令還是訪問資料,所訪問的 儲存單元 都趨於聚集在乙個較小的連續區域中。三種不同型別的區域性性 時間區域性性 temporal locality 如果乙個資訊項正在被訪問,那麼在近期它很可能還會被再次訪問。程式迴圈 堆疊等是產生時間區域性性的原因。順序區...
區域性性原理
區域性性通常有兩種不同的形式 時間區域性性和空間區域性性。時間區域性性 在乙個具有良好的時間區域性性的程式中,被訪問過一次的儲存器位置很可能在不遠的將來會被再次訪問。空間區域性性 在乙個具有良好空間區域性性的程式中,如果乙個儲存器位置被訪問了一次,那麼程式很可能在不遠的將來訪問附近的乙個儲存器位置。...
區域性性原理
平常在服務端軟體開發中,通常會把資料儲存在資料庫裡,服務端遇到的效能瓶頸往往發生在訪問資料庫的時候,在資料庫前通過redis加資料快取是常見的效能優化方式。如何判定新增快取的策略一定是有效的呢?不同的儲存器之間,訪問速度 和容量都有幾十乃至上千倍的差異。在效能和 的巨大差異,能不能既享受cpu ca...