我猜應(yīng)該很多人都有這樣的困惑,就是覺(jué)得學(xué)計(jì)組有什么用?感覺(jué)實(shí)際工作過(guò)程中用不到,感覺(jué)理論學(xué)了個(gè)寂寞。這個(gè)困惑很正常,因?yàn)閷W(xué)計(jì)組這東西主要是為了搞懂計(jì)算機(jī)是如何工作的,計(jì)算機(jī)怎么工作的都是被前輩們實(shí)現(xiàn)好的,我們一般也不會(huì)參與到造計(jì)算機(jī)這種工作中。但是學(xué)了計(jì)組后,你能看到的視角是和別人不一樣的,而這個(gè)不一樣的視角就能在一些關(guān)鍵的問(wèn)題上得到突破。我這里舉個(gè)簡(jiǎn)單例子,你覺(jué)得下面這兩個(gè)?for?循環(huán)哪個(gè)效率會(huì)更高呢?為什么會(huì)更高呢?這個(gè)問(wèn)題的關(guān)鍵在于,大家知不知道 CPU Cache 這個(gè)東西。我自己曾經(jīng)在還沒(méi)有學(xué)計(jì)組的時(shí)候,只覺(jué)得存儲(chǔ)設(shè)備就是我們常見(jiàn)的內(nèi)存和硬盤(pán),學(xué)了后我才發(fā)現(xiàn)還有 CPU Cache 這個(gè)東西,而能不能充分利用到這個(gè)東西,就決定你程序的性能。CPU Cache 是 CPU 內(nèi)部的一個(gè)緩存,它的讀寫(xiě)速度遠(yuǎn)高于內(nèi)存,所以它充當(dāng)內(nèi)存的緩存角色,當(dāng) CPU 要訪問(wèn)的數(shù)據(jù)命中了 CPU Cache,就不用去從內(nèi)存上找數(shù)據(jù),就像 MySQL 和 Redis 之間的關(guān)系。CPU Cache 一般會(huì)分為三層,分別是 L1 Cache、L2 Cache、L3 Cache ,其中 L1 Cache 是各個(gè) CPU 核心獨(dú)立的,剩下的 L2 Cache、L3 Cache 是各個(gè)核心共享的。CPU Cache 的數(shù)據(jù)是從內(nèi)存中讀取過(guò)來(lái)的,它是以一小塊一小塊讀取數(shù)據(jù)的,而不是按照單個(gè)數(shù)組元素來(lái)讀取數(shù)據(jù)的,在 CPU Cache 中的,這樣一小塊一小塊的數(shù)據(jù),稱(chēng)為 Cache Line(緩存塊)。?如果 L1 Cache Line 大小是 64 字節(jié),也就意味著 L1 Cache 一次載入數(shù)據(jù)的大小是 64 字節(jié)。比如,有一個(gè) int array[100] 的數(shù)組,當(dāng)載入 array[0] 時(shí),由于這個(gè)數(shù)組元素的大小在內(nèi)存只占 4 字節(jié),不足 64 字節(jié),CPU 就會(huì)順序加載數(shù)組元素到 array[15] ,意味著 array[0]~array[15] 數(shù)組元素都會(huì) 被緩存在 CPU Cache 中了,因此當(dāng)下次訪問(wèn)這些數(shù)組元素時(shí),會(huì)直接從 CPU Cache 讀取,而不用再?gòu)膬?nèi) 存中讀取,大大提高了 CPU 讀取數(shù)據(jù)的性能。CPU Cache 的概念簡(jiǎn)單介紹完了,再來(lái)說(shuō)說(shuō)剛才的 for 循環(huán)問(wèn)題。我直接說(shuō)答案:形式一?array[i][j]?執(zhí)行時(shí)間比形式二?array[j][i]?快好幾倍。之所以有這么大的差距,是因?yàn)槎S數(shù)組?array?所占用的內(nèi)存是連續(xù)的,比如長(zhǎng)度?N?的指是?2?的話(huà),那么內(nèi)存中的數(shù)組元素的布局順序是這樣的:形式一用?array[i][j]?訪問(wèn)數(shù)組元素的順序,正是和內(nèi)存中數(shù)組元素存放的順序一致。當(dāng) CPU 訪問(wèn)?array[0][0]?時(shí),由于該數(shù)據(jù)不在 Cache 中,于是會(huì)「順序」把跟隨其后的 3 個(gè)元素從內(nèi)存中加載到 CPU Cache,這樣當(dāng) CPU 訪問(wèn)后面的 3 個(gè)數(shù)組元素時(shí),就能在 CPU Cache 中成功地找到數(shù)據(jù),這意味著緩存命中率很高,緩存命中的數(shù)據(jù)不需要訪問(wèn)內(nèi)存,這便大大提高了代碼的性能。而如果用形式二的?array[j][i]?來(lái)訪問(wèn),則訪問(wèn)的順序就是:你可以看到,訪問(wèn)的方式跳躍式的,而不是順序的,那么如果 N 的數(shù)值很大,那么操作?array[j][i]?時(shí),是沒(méi)辦法把?array[j 1][i]?也讀入到 CPU Cache 中的,既然?array[j 1][i]沒(méi)有讀取到 CPU Cache,那么就需要從內(nèi)存讀取該數(shù)據(jù)元素了。很明顯,這種不連續(xù)性、跳躍式訪問(wèn)數(shù)據(jù)元素的方式,可能不能充分利用到了 CPU Cache 的特性,從而代碼的性能不高。那訪問(wèn)?array[0][0]?元素時(shí),CPU 具體會(huì)一次從內(nèi)存中加載多少元素到 CPU Cache 呢?這個(gè)問(wèn)題,在前面我們也提到過(guò),這跟 CPU Cache Line 有關(guān),它表示?CPU Cache 一次性能加載數(shù)據(jù)的大小,可以在 Linux 里通過(guò)?coherency_line_size?配置查看 它的大小,通常是 64 個(gè)字節(jié)。也就是說(shuō),當(dāng) CPU 訪問(wèn)內(nèi)存數(shù)據(jù)時(shí),如果數(shù)據(jù)不在 CPU Cache 中,則會(huì)一次性會(huì)連續(xù)加載 64 字節(jié)大小的數(shù)據(jù)到 CPU Cache,那么當(dāng)訪問(wèn)?array[0][0]?時(shí),由于該元素不足 64 字節(jié),于是就會(huì)往后順序讀取?array[0][0]~array[0][15]?到 CPU Cache 中。順序訪問(wèn)的?array[i][j]?因?yàn)槔昧诉@一特點(diǎn),所以就會(huì)比跳躍式訪問(wèn)的?array[j][i]?要快。因此,遇到這種遍歷數(shù)組的情況時(shí),按照內(nèi)存布局順序訪問(wèn),將可以有效的利用 CPU Cache 帶來(lái)的好處,這樣我們代碼的性能就會(huì)得到很大的提升,CPU Cache 的內(nèi)容遠(yuǎn)不止于我說(shuō)的這些,還有緩存一致性協(xié)議、偽共享、write through 和 write back 的方式等,這些都是非常重要的知識(shí)。
第五章:層次化存儲(chǔ),講的是計(jì)算機(jī)的存儲(chǔ)層次結(jié)構(gòu),而且重點(diǎn)講的是 CPU Cahe。
計(jì)算機(jī)組成原理視頻課程
看書(shū)覺(jué)得很累,也可以結(jié)合視頻一起看,這里推薦哈工大的《計(jì)算機(jī)組成原理》視頻,在 b 站就可以直接看,大家自己去搜索就可以。看書(shū)和看視頻可以相互結(jié)合的,比如你看視頻看了計(jì)算機(jī)指令的內(nèi)容,然后你可以不用繼續(xù)往下看,可以回到一本書(shū)上,看書(shū)上對(duì)應(yīng)這個(gè)章節(jié)的內(nèi)容,這是個(gè)很好的學(xué)習(xí)方法,視頻和書(shū)籍相輔相成。你要是覺(jué)得哈工大的計(jì)組課程太難,你可以看王道考研的計(jì)算機(jī)組成原理的視頻課程,同樣 b 站就可以看。這個(gè)視頻雖然是針對(duì)考研的,但是也是可以作為學(xué)習(xí)計(jì)組的資料,講的內(nèi)容不會(huì)太深,適合你快速建立計(jì)算機(jī)組成原理體系,和梳理計(jì)組知識(shí)的脈絡(luò)。
其他重合的計(jì)組知識(shí)都大同小異。CSAPP 的視頻課程是國(guó)外老師錄制的,但是在 b 站已經(jīng)有好人幫我們做了中文字幕,看了這視頻,相當(dāng)于在國(guó)外上了一門(mén)計(jì)算機(jī)課的感覺(jué)。如果你是在校生,有了一定 C 語(yǔ)言基礎(chǔ)后,非常建議你就開(kāi)始看這本書(shū),有精力也可以做做 CSAPP 的 lab。越早開(kāi)始看,你的收益就越大,因?yàn)楫?dāng)計(jì)算機(jī)體系搭建起來(lái)后,你后面再深入每一個(gè)課程的時(shí)候,你會(huì)發(fā)現(xiàn)學(xué)起來(lái)會(huì)比較輕松些。對(duì)于已經(jīng)工作了,但是計(jì)算機(jī)系統(tǒng)沒(méi)有一個(gè)清晰認(rèn)識(shí)的讀者,也可以從這本書(shū)開(kāi)始一點(diǎn)一點(diǎn)學(xué)起來(lái),這本書(shū)是很厚,但是并不一定要把書(shū)完完看完,每個(gè)章節(jié)的知識(shí)點(diǎn)還是比較獨(dú)立的,有關(guān)硬件的章節(jié)我們可以選擇跳過(guò)。這就是我學(xué)計(jì)組的心得啦。沒(méi)學(xué)過(guò)計(jì)組的同學(xué),可以找個(gè)時(shí)間補(bǔ)補(bǔ)了,提高下自己的「內(nèi)功」。干就完啦!