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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

程序局部性原理感悟

發(fā)布時(shí)間:2023/12/31 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序局部性原理感悟 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
局部性原理 程序的局部性原理是指程序在執(zhí)行時(shí)呈現(xiàn)出局部性規(guī)律,即在一段時(shí)間內(nèi),整個(gè)程序的執(zhí)行僅限于程序中的某一部分。相應(yīng)地,執(zhí)行所訪問(wèn)的存儲(chǔ)空間也局限于某個(gè)內(nèi)存區(qū)域。 局部性原理又表現(xiàn)為:時(shí)間局部性和空間局部性。 時(shí)間局部性是指如果程序中的某條指令一旦執(zhí)行,則不久之后該指令可能再次被執(zhí)行;如果某數(shù)據(jù)被訪問(wèn),則不久之后該數(shù)據(jù)可能再次被訪問(wèn)。 空間局部性是指一旦程序訪問(wèn)了某個(gè)存儲(chǔ)單元,則不久之后。其附近的存儲(chǔ)單元也將被訪問(wèn)。 這一規(guī)律是是普遍事實(shí)的總結(jié),更是許多計(jì)算機(jī)技術(shù)的前提假設(shè),比如.NET中托管堆以及代齡的處理過(guò)程,便是基于這個(gè)認(rèn)識(shí)。 之所以有這個(gè)規(guī)律,很多人認(rèn)為原因是:程序的指令大部分時(shí)間是順序執(zhí)行的,而且程序的集合,如數(shù)組等各種數(shù)據(jù)結(jié)構(gòu)是連續(xù)存放的。對(duì)于這一點(diǎn),我個(gè)人表示贊同。 程序的局部性原理是如此重要,以至于與程序設(shè)計(jì)的各個(gè)方面都存在密切的關(guān)系。 局部性與效率 熟悉代碼的局部性原理,并且按照這個(gè)思路去寫代碼,可以顯著的提高代碼的執(zhí)行效率,先看下面的C#代碼: static void Main(string[] args) {int[,] a = new int[10000,10000];int sum = 0;// 按照先行后列的順序遍歷二維數(shù)組,這是正常做法WriteTimes(() =>{for (int i = 0; i < 10000; i++){for (int j = 0; j < 10000; j++){sum += a[i, j];}}});// 按照先列后行的順序遍歷二維數(shù)組,這是異常做法WriteTimes(() =>{for (int j = 0; j < 10000; j++){for (int i = 0; i < 10000; i++){sum += a[i, j];}}});Console.Read(); }static void WriteTimes(Action func) {DateTime dt0 = DateTime.Now;func();DateTime dt1 = DateTime.Now;Console.WriteLine((dt1 - dt0).Milliseconds); }

  大家可以輸出一下,在我的機(jī)器上的輸出為(具體的數(shù)值可能不同,但是大小比例應(yīng)該差不多):

102 999

  這個(gè)例子本身并沒什么實(shí)際的意義,但如果處理的數(shù)據(jù)量足夠大,并且可能需要頻繁的在外存、內(nèi)存、緩存間調(diào)度,又注重效率的話,這個(gè)問(wèn)題就有可能會(huì)被陡然放大了。不過(guò),通常來(lái)說(shuō),效率總是在程序出現(xiàn)性能問(wèn)題后才應(yīng)該被關(guān)注的方面

局部性與緩存 歸根結(jié)底,緩存(各種緩存技術(shù),CPU緩存,數(shù)據(jù)庫(kù)緩存,服務(wù)器緩存)探討的也基本都是效率的問(wèn)題,看另一個(gè)來(lái)源于網(wǎng)上某位仁兄的問(wèn)題: // 寫法一:循環(huán)內(nèi)塞進(jìn)好幾件事 for (int i = 0; i < 1000; i++) {WriteIntArray();WriteStringArray(); } // 寫法二:循環(huán)內(nèi)只干一件事 for (int i = 0; i < 1000; i++) {WriteIntArray(); } for (int i = 0; i < 1000; i++) {WriteStringArray(); }

問(wèn):兩種寫法哪個(gè)好?

有的同學(xué)認(rèn)為寫法一效率高,因?yàn)檠h(huán)只執(zhí)行了一遍,而有的同學(xué)認(rèn)為寫法二效率高,因?yàn)樵搶懛ㄖ忻總€(gè)循環(huán)內(nèi)的局部變量大部分情況下是比寫法一少,這樣更容易利用CPU的寄存器以及各級(jí)緩存,這滿足局部性原理,所以效率較好。 我寫了簡(jiǎn)單的程序驗(yàn)證了一下,發(fā)現(xiàn)確實(shí)有時(shí)候?qū)懛ㄒ粓?zhí)行時(shí)間較短,有時(shí)候?qū)懛ǘ?zhí)行之間較短,沒有明顯的固定規(guī)律,所以我認(rèn)為這里的效率一說(shuō)不太明顯,當(dāng)然了也許是這里的循環(huán)次數(shù)比較少,循環(huán)多次的低效還沒有體現(xiàn)出來(lái),感興趣的可以自己試一下大的循環(huán)。 即使是這樣的結(jié)果,我還是傾向于使用第二種寫法,這不是效率的原因,而是重構(gòu)中,提倡一個(gè)循環(huán)只干一件事。 局部性與重構(gòu) 重構(gòu)的基本原理這里就不多說(shuō)了,感興趣的隨便搜一下就可以了。重構(gòu)的基本原則中就有諸如:一個(gè)循環(huán)只干好一件事,關(guān)聯(lián)性強(qiáng)的代碼放到一起,變量定義在使用的地方等等。這些原則與局部性原理闡述的規(guī)律竟然是如出一轍。 看一些我認(rèn)可的寫法: // 一個(gè)循環(huán)內(nèi)只干好一件事 for (int i = 0; i < 1000; i++) {WriteIntArray(); } for (int i = 0; i < 1000; i++) {WriteStringArray(); }// 原始的代碼 List<int> salaryList = new List<int>(); List<int> levelList = new List<int>(); List<int> scoreList = new List<int>();collectHighSalary(salaryList); collectHighLevel(levelList); collectHighScore(scoreList);collectMiddleSalary(salaryList); collectMiddleLevel(levelList);collectLowSalary(salaryList); collectLowlevel(levelList); // 重構(gòu)成: // 有關(guān)系的代碼放到一起 // 變量需要時(shí)再定義 List<int> salaryList = new List<int>(); collectHighSalary(salaryList); collectMiddleSalary(salaryList); collectLowSalary(salaryList);List<int> levelList = new List<int>(); collectHighLevel(levelList); collectMiddleLevel(levelList); collectLowlevel(levelList);List<int> scoreList = new List<int>(); collectHighScore(scoreList);

  局部性原理不僅與語(yǔ)句和函數(shù)的組織方式息息相關(guān),還與組件的組織方式互相呼應(yīng)。

局部性與高內(nèi)聚 從元素(函數(shù),對(duì)象,組件,乃至服務(wù))設(shè)計(jì)的角度,內(nèi)聚性是描述一個(gè)元素的成員之間關(guān)聯(lián)性強(qiáng)弱尺度。如果一個(gè)元素具有很多緊密相關(guān)的成員,而且它們有機(jī)的結(jié)合在一起去完成有限的相關(guān)功能,那這個(gè)元素通常就是高度內(nèi)聚的。高內(nèi)聚的設(shè)計(jì)是一種良好的設(shè)計(jì)。 耦合性從另一個(gè)角度描述了元素之間的關(guān)聯(lián)性強(qiáng)弱。元素之間聯(lián)系越緊密,其耦合性就越強(qiáng),元素的獨(dú)立性則越差,元素間耦合的高低取決于元素間接口的復(fù)雜性,調(diào)用的方式以及傳遞的信息。低耦合的設(shè)計(jì)是一種良好的設(shè)計(jì)。 一個(gè)具有低內(nèi)聚,高耦合的元素會(huì)執(zhí)行許多互不相關(guān)的邏輯,或者完成太多的功能,這樣的元素難于理解、難于重用、難于維護(hù),常常導(dǎo)致系統(tǒng)脆弱,常常受到變化帶來(lái)的困擾。 毫無(wú)疑問(wèn),遵循良好的局部性原理通常能得到良好的高內(nèi)聚低耦合元素,反之,代碼中元素的高內(nèi)聚低耦合也使的局部性得以大大加強(qiáng),此所謂相得益彰。 局部性與命名 說(shuō)到命名,不得不提著名的匈牙利命名法。 在我讀了《軟件隨想錄:程序員部落酋長(zhǎng)Joel談軟件》一書之前,我認(rèn)為的匈牙利命名法則就是在駝峰式命名的基礎(chǔ)上,在變量名前加上變量的類型,例如iLength表示int型的表示長(zhǎng)度的變量。 但是在我閱讀了《軟件隨想錄》一書相關(guān)的章節(jié)以后,才徹底的了解到其中的誤解。原來(lái)微軟那位大牛推薦的匈牙利命名法居然不是我想的那樣。 在該書中,作者將匈牙利命名法分為兩種,流行的并且被廢掉的叫“系統(tǒng)型匈牙利命名法則”,這種命名法將變量類型加到了變量名字前面,老實(shí)說(shuō)確實(shí)沒什么意義,特別是在現(xiàn)代編輯器中。 事實(shí)上,微軟那位仁兄推薦的是叫做“應(yīng)用型匈牙利命名法則”的規(guī)則,那就是把變量的應(yīng)用場(chǎng)景加到變量的名字前面。 比如在頁(yè)面開發(fā)中,直接從用戶輸入得到的Name字符串可以起名叫:usName,其中us代表unsafe,意思是這個(gè)字符串是用戶輸入的,沒用經(jīng)過(guò)編碼處理,可能是不安全的。而經(jīng)過(guò)編碼的Name字符串可以起名叫sName,其中s代表safe,意思是這個(gè)字符串經(jīng)過(guò)了編碼處理,是安全的。 談到命名的規(guī)則,就是為了說(shuō)明下面這個(gè)息息相關(guān)的問(wèn)題:代碼錯(cuò)誤檢查。 代碼錯(cuò)誤檢查也是一個(gè)經(jīng)典的話題,如何讓代碼的錯(cuò)誤提前暴露出來(lái),而不是發(fā)布后由客戶去發(fā)現(xiàn),這是個(gè)問(wèn)題。 滿足局部性原理,使得我們的程序內(nèi)聚性通常很好,但是毫無(wú)疑問(wèn),有些元素還是必須要貫穿很多的行的,比如在某些函數(shù)中,定義變量和末次使用變量的地方可能相差幾十行: var usName = getName(); action1(usName); // 此處省略20行... sName = usName; // 此處省略10行... document.write(sName);

  我不得不承認(rèn),Joel老兄提出的“應(yīng)用型匈牙利命名法則”還是相當(dāng)有作用的。比如中間那行:

sName = usName;

  我們很容易就會(huì)從變量名發(fā)現(xiàn)這行代碼存在安全性威脅。

我們其實(shí)生活在世界的局部中 推而廣之,局部性原理不僅僅是適用于程序的理論,而是適用于我們生活的各個(gè)方面的重要規(guī)律,它的稱呼向來(lái)隨著場(chǎng)合的不同而有所變化,比如有時(shí)叫“習(xí)慣”,有時(shí)叫“慣性”,有時(shí)又演化成“熟悉的人/事”等。總之,我個(gè)人認(rèn)為,人總是傾向于在局部的、連續(xù)的時(shí)間空間內(nèi)做相關(guān)的、熟悉的事情,程序其實(shí)是人類做事風(fēng)格的反應(yīng)。

總結(jié)

以上是生活随笔為你收集整理的程序局部性原理感悟的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。