開篇
一個優秀的程序、優美的代碼,一般都具有良好的局部性。簡潔、高效是每個程序員的追求。了解程序的局部性,能編寫出更高效的代碼。
因為有良好局部性的程序能更好的利用緩存。不過這方面的只是將在以后的文章中介紹。
這篇文章就簡單的介紹以下程序的局部性原理。
什么是局部性
局部性通常有兩種形式:
時間局部性(temporal locality)
時間局部性指的是:被引用過一次的存儲器位置在未來會被多次引用(通常在循環中)。
空間局部性(spatial locality)
如果一個存儲器的位置被引用,那么將來他附近的位置也會被引用。
(這樣說過於理論了些,在下面的論述中會有例子說明)
數據引用局部性
例子是最好說明問題的途徑~
看圖a)中的 for 循環,可以判斷:循環中的 sum 有良好的時間局部性。因為在for循環結束之前,每次執行循環體都有對 sum 的訪問。
而 sum 沒有空間局部性。因為sum 是標量(也就是說通過 sum 這個地址(可認為是基址,只能得到一個值)
對於循環體中的 v 則有良好的空間局部性。可以看到 圖 b) 中,向量 v 是按順序存儲的(在實際中多數情況也按順序存儲)。
每次訪問 v[i]總是在 v[i-1] 的下一個位置。而 v 沒有時間局部性。因為每個元素只被訪問一次。
步長
向上面例子中按順序、連續的對 v 的引用,我們稱為步長為1的引用模式。同理,在一個連續的向量中,每隔k個元素對向量進行訪問,稱為步長為k的引用。一般來說,隨着步長的增加,空間局部性會下降。
對於多維數組而言,步長對空間局部性的影響顯得尤為重要。
考慮上面的例子,是對一個二維數組的求和。
可以看到,for循環體中,是以行序為主序對元素進行遍歷。也就是說內層循環先訪問第一行的元素,然后第二行。。。
圖 b)中是二維數組存儲情況。可以看出,在存儲器中也是按照行序為主序來進行存儲的。也就是說先存儲第一行,然后第二行。。。
現在我們已經知道了,本例中存儲順序和訪問順序一致。所以可以該程序對a[][]的引用有良好的空間局部性。
對a[][]實行的是步長為1 的引用。
繼續看下面的例子:
可以看出,相對於上面的例子,該例的for 循環中交換了 索引 i j 的位置。
也就是說在對a[][]進行遍歷的時候,以列序為主序。即先訪問第一列,在訪問第二列。。。
而b)中,對a[][]的存儲仍是行序為主序。這意味着沒訪問一個元素,就要跳過k個存儲器才能訪問下一個。於是得到一個簡單的結論:該例中對a[][]的訪問是以步長為k 的模式(k 為每行的元素個數)沒有良好的時間局部性。
通過上面的例子我們知道:在對向量的訪問中,如果訪問數序和存儲順序一致,並且是連續訪問,那么這種訪問具有良好的空間局部性。
取指令的局部性
指令存在於存儲器中,cpu 要讀指令就必須取出指令。所以也能評價對於取指令的局部性。
在for 循環中,循環體內的指令多次被執行,所以有良好的時間局部性。
循環體中的指令是桉順序執行的,有良好的空間局部性(指令在存儲器中是順序存放的)。
局部性小結
評價局部性的簡單原則:
1、重復引用同一個變量有良好的時間局部性
2、對於步長為k 的引用的程序,步長越小,空間局部性越小。步長為1 的引用具有良好的空間局部性。k越大,空間局部性越差。
3、對於取指令來說、循環有較好的時間和空間局部性。
后記
這篇文章只是簡單的介紹了什么是局部性,局部性原理的應有,即為什么有良好局部性的程序有更好的性能,局部性和告訴緩存的關系是如何的,將在后面的文章中介紹。這篇文章且當作后文的鋪墊吧。
本人認知有限,如上述文章有不足之處歡迎指正交流。
參看資料:computer systems
如有轉載請注明出處:http://www.cnblogs.com/yanlingyin/
一條魚、yanlingyin@ 博客園 2012-2-11
E-mail:yanlingyin@yeah.net