在這一節內容開始以前,咱們先來看一個3行的小程序。你能夠猜一猜,這個程序裏的循環1和循環2,運行所花費的時間會差多少?你能夠先思考幾分鐘,而後再看我下面的解釋java
int[] arr = new int[64 * 1024 * 1024]; // 循環 1 for (int i = 0; i < arr.length; i++) arr[i] *= 3; // 循環 2 for (int i = 0; i < arr.length; i += 16) arr[i] *= 3
在這段Java程序中,咱們首先構造了一個64×1024×1024大小的整型數組。在循環1裏,咱們遍歷整個數組,將數組中每一項的值變成了原來的3倍;在循環2裏,小程序
咱們每隔16個索引訪問一個數組元素,將這一項的值變成了原來的3倍。
數組
按道理來講,循環2只訪問循環1中1/16的數組元素,只進行了循環1中1/16的乘法計算,那循環2花費的時間應該是循環1的1/16左右。緩存
可是實際上,循環1在個人電腦上運行須要50毫秒,循環2只須要46毫秒。這兩個循環花費時間之差在15%以內。網絡
爲何會有這15%的差別呢?這和咱們今天要講的CPU Cache有關。以前咱們看到了內存和硬盤之間存在的巨大性能差別。在CPU眼裏,內存也慢得不行。
因而,聰明的工程師們就在CPU裏面嵌入了CPU Cache(高速緩存),來解決這一問題。數據結構
好比說,咱們的主內存被分紅0~31號這樣32個塊、咱們一共有8個緩存塊。用戶想要訪問第21號內存塊性能
若是21號內存塊內容在緩存塊中的話,它必定在5號緩存塊(21 mod 8 = 5)中spa
剛纔我花了不少篇幅,講了CPU和內存之間的性能差別,以及咱們如何經過CPU Cache來儘量解決這二者之間的性能鴻溝。
你可能要問了,這樣作的意義和價值到底是什麼?畢竟,一次內存的訪問,只不過須要100納秒而已。1秒鐘時間內,足有1000萬個100納秒。
彆着急,咱們先來看一個故事。設計
2008年,一家叫做Spread Networks的通訊公司花費3億美圓,作了一個光纜建設項目。目標是建設一條從芝加哥到新澤西總長1331千米的光纜線路。建設這條線路的目的,
實際上是爲了將兩地之間原有的網絡訪問延時,從17毫秒下降到13毫秒。
你可能會說,僅僅縮短了4毫秒時間啊,卻花費3個億,真的值嗎?爲這4毫秒時間買單的,實際上是一批高頻交易公司。它們以5年1400萬美圓的價格,使用這條線路。利用這短短的4毫秒的時間優點,這些公司經過高性能的計算機程序,在芝加哥和新澤西兩地的交易所進行高頻套利,以得到每一年以10億美圓計的利潤。如今你還以爲這個不值得嗎?
其實,只要350微秒的差別,就足夠高頻交易公司用來進行無風險套利了。而350微秒,若是用來進行100納秒一次的內存訪問,大約只夠進行3500次。
而引入CPU Cache以後,咱們能夠進行的數據訪問次數,提高了數十倍,使得各類交易策略成爲可能。3d
不少時候,程序的性能瓶頸,來自使用DRAM芯片的內存訪問速度。
根據摩爾定律,自上世紀80年代以來,CPU和內存的性能鴻溝越拉越大。因而,現代CPU的設計者們,直接在CPU中嵌入了使用更高性能的SRAM芯片的Cache,
來彌補這一性能差別。經過巧妙地將內存地址,拆分紅「索引+組標記+偏移量」的方式,使得咱們能夠將很大的內存地址,映射到很小的CPU Cache地址裏。
而CPU Cache帶來的毫秒乃至微秒級別的性能差別,又能帶來巨大的商業利益,十多年前的高頻交易行業就是最好的例子。
在搞清楚從內存加載數據到Cache,以及從Cache裏讀取到想要的數據以後,咱們又要面臨一個新的挑戰了。CPU不只要讀數據,還須要寫數據,
咱們不能只把數據寫入到Cache裏面就結束了。下一講,咱們就來仔細講講,CPU要寫入數據的時候,怎麼既不犧牲性能,又能保證數據的一致性。