聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响
Java作為一個跨平臺的語言,它的實現要面對不同的底層硬件系統,設計一個中間層模型來屏蔽底層的硬件差異,給上層的開發者一個一致的使用接口。Java內存模型就是這樣一個中間層的模型,它為程序員屏蔽了底層的硬件實現細節,支持大部分的主流硬件平臺。要理解Java內存模型以及一些處理高并發的技術手段,理解一些基本的硬件知識是必須的。這篇會說一下跟并發編程相關的一些硬件知識。
?
一個基本的CPU執行計算的過程如下:
1. 程序以及數據被加載到主內存
2. 指令和數據被加載到CPU的高速緩存
3. CPU執行指令,把結果寫到高速緩存
4. 高速緩存中的數據寫回主內存
?
這個過程中,我們可以看到有兩個問題
1. 現代的計算芯片都會集成一個L1高速緩存,我們可以理解為每個芯片都有一個私有的存儲空間。那么當CPU的不同計算芯片要訪問同一個內存地址時,該內存地址的值會在CPU的不同計算芯片之間有多個拷貝,如何同步這些拷貝?
2. CPU讀寫是直接和高速緩存打交道,而不是和主內存直接打交道。因為通常一次主存訪問在幾十到幾百個時鐘周期,而一次L1高速緩存的讀寫只需要1-2個時鐘周期,而一次L2高速緩存的讀寫只需要數十個時鐘周期。那么CPU寫到高速緩存的值何時寫回到主內?如果是多個計算芯片在處理同一個內存地址,那么如何處理這個時間差是個問題。
?
對于第一個問題,不同的硬件結構處理的方式不一樣。我們來理解一下互連線的概念。
互連線是處理器于主存以及處理器與處理器之間進行通信的媒介,有兩種基本的互聯結構:SMP(symmetric multiprocessing 對稱多處理)和NUMA(nonuniform memory access 非一致內存訪問)
SMP系統結構非常普通,因為它們最容易構建,很多小型服務器采用這種結構。處理器和存儲器之間采用總線互聯,處理器和存儲器都有負責發送和監聽總線廣播的信息的總線控制單元。但是同一時刻只能有一個處理器(或存儲控制器)在總線上廣播,所有的處理器都可以監聽。
很容易看出,對總線的使用是SMP結構的瓶頸。
?
NUMP系統結構中,一系列節點通過點對點網絡互聯,像一個小型互聯網,每個節點包含一個或多個處理器和一個本地存儲器。一個節點的本地存儲對于其他節點是可見的,所有節點的本地存儲一起形成了一個可以被所有處理器共享的全局存儲器。可以看出,NUMP的本地存儲是共享的,而不是私有的,這點和SMP是不同的。NUMP的問題是網絡比總線復制,需要更加復雜的協議,處理器訪問自己節點的存儲器速度快于訪問其他節點的存儲器。NUMP的擴展性很好,所以目前很多大中型的服務器在采用NUMP結構。
?
對于上層程序員來說,最需要理解的是互連線是一種重要的資源,使用的好壞會直接影響程序的執行性能。
?
大概理解了不同的互連結構之后,我們來看看緩存一致性協議。它主要就是處理多個處理器處理同一個主存地址的問題。
MESI是一種主流的緩存一致性協議,已經用在Pentium和PowerPC處理器中。它定義了緩存塊的幾種狀態
- modified(修改):緩存塊已經被修改,必須被寫回主存,其他處理器不能再緩存這個塊
- exclusive(互斥):緩存塊還沒有被修改,且其他處理器不能裝入這個緩存塊
- share(共享):緩存塊未被修改,且其他處理器可以裝入這個緩存塊
- invalid(無效):緩存塊中的數據無效
上圖展示了MESI高速緩存一致性協議的狀態轉換實例。
1. 在a中,處理器A從地址a讀取數據,將數據存入它的緩存并置為exclusive
2. 在b中,當處理器B試圖從相同地址a讀取數據時,A檢測到地址沖突,以相關數據做出響應。此時a同時被A和B以shared狀態裝入緩存
3. 在c中,當B要對共享地址a進行寫操作,則將狀態改為modified,并廣播提醒A,讓它將它的緩存塊狀態設置為Invalid
4. 在d中,當A試圖從a讀取數據,會廣播它的請求,B則把它修改的數據發送到A和主存,并設置兩個副本的狀態為shared來做出響應
?
更多緩存一致性協議的細節參考這篇?http://blog.csdn.net/realxie/article/details/7317630
?
緩存一致性協議存在的一個最大的問題是可能引起緩存一致性流量風暴,之前我們看到總線在同一時刻只能被一個處理器使用,當有大量緩存被修改,或者同一個緩存塊一直被修改時,會產生大量的緩存一致性流量,從而占用總線,影響了其他正常的讀寫請求。
?
一個最常見的例子就是如果多個線程對同一個變量一直使用CAS操作,那么會有大量修改操作,從而產生大量的緩存一致性流量,因為每一次CAS操作都會發出廣播通知其他處理器,從而影響程序的性能。
?
后面我們會講如何優化這種使用方式。
?
對于第二個問題,如何處理修改數據從高速緩存到主內存的時間差,通常使用內存屏障來處理,后面會有專門的主題。
?
轉載請注明來源:http://blog.csdn.net/iter_zc
總結
以上是生活随笔為你收集整理的聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊聊高并发(四)Java对象的表示模型和
- 下一篇: 聊聊高并发(六)实现几种自旋锁