- 原文地址:medium.com/@genchilu/w…
- 原文做者:Genchi Lu
- 譯文地址:github.com/watermelo/d…
- 譯者:咔嘰咔嘰
- 譯者水平有限,若有翻譯或理解謬誤,煩請幫忙指出
在解釋緩存 false sharing 以前,有必要簡要介紹一下緩存在 CPU 架構中的工做原理。git
CPU 中緩存的最小化單位是緩存行(如今來講,CPU 中常見的緩存行大小爲 64 字節)。所以,當 CPU 從內存中讀取變量時,它將讀取該變量附近的全部變量。圖 1 是一個簡單的例子:github
當 core1 從內存中讀取變量 a 時,它會同時將變量 b 讀入緩存。(順便說一下,我認爲 CPU 從內存中批量讀取變量的主要緣由是基於空間局部性理論:當 CPU 訪問一個變量時,它可能很快就會讀取它旁邊的變量。)(譯者注:關於空間局部性理論能夠參考這篇文章)golang
該緩存架構存在一個問題:若是一個變量存在於不一樣 CPU 核心中的兩個緩存行中,如圖 2 所示:shell
當 core1 更新變量 a 時:緩存
當 core2 讀取變量 b 時,即便變量 b 未被修改,它也會使 core2 的緩存未命中。因此 core2 會從內存中從新加載緩存行中的全部變量,如圖 4 所示:bash
這就是緩存 false sharing:一個 CPU 核更新變量會強制其餘 CPU 核更新緩存。而咱們都知道從緩存中讀取 CPU 的變量比從內存中讀取變量要快得多。所以,雖然該變量一直存在於多核中,但這會顯著影響性能。架構
解決該問題的經常使用方法是緩存填充:在變量之間填充一些無心義的變量。使一個變量單獨佔用 CPU 核的緩存行,所以當其餘核更新時,其餘變量不會使該核從內存中從新加載變量。性能
咱們使用以下的 Go 代碼來簡要介紹緩存 false sharing 的概念。測試
這是一個帶有三個 uint64 變量的結構體,ui
type NoPad struct {
a uint64
b uint64
c uint64
}
func (myatomic *NoPad) IncreaseAllEles() {
atomic.AddUint64(&myatomic.a, 1)
atomic.AddUint64(&myatomic.b, 1)
atomic.AddUint64(&myatomic.c, 1)
}
複製代碼
這是另外一個結構,我使用 [8]uint64 來作緩存填充:
type Pad struct {
a uint64
_p1 [8]uint64
b uint64
_p2 [8]uint64
c uint64
_p3 [8]uint64
}
func (myatomic *Pad) IncreaseAllEles() {
atomic.AddUint64(&myatomic.a, 1)
atomic.AddUint64(&myatomic.b, 1)
atomic.AddUint64(&myatomic.c, 1)
}
複製代碼
而後寫一個簡單的代碼來運行基準測試:
func testAtomicIncrease(myatomic MyAtomic) {
paraNum := 1000
addTimes := 1000
var wg sync.WaitGroup
wg.Add(paraNum)
for i := 0; i < paraNum; i++ {
go func() {
for j := 0; j < addTimes; j++ {
myatomic.IncreaseAllEles()
}
wg.Done()
}()
}
wg.Wait()
}
func BenchmarkNoPad(b *testing.B) {
myatomic := &NoPad{}
b.ResetTimer()
testAtomicIncrease(myatomic)
}
func BenchmarkPad(b *testing.B) {
myatomic := &Pad{}
b.ResetTimer()
testAtomicIncrease(myatomic)
}
複製代碼
使用 2014 年的 MacBook Air 作的基準測試結果以下:
$> go test -bench=.
BenchmarkNoPad-4 2000000000 0.07 ns/op
BenchmarkPad-4 2000000000 0.02 ns/op
PASS
ok 1.777s
複製代碼
基準測試的結果代表它將性能從 0.07 ns/op 提升到了 0.02 ns/op,這是一個很大的提升。
你也能夠用其餘語言測試這個,好比 Java,我相信你會獲得相同的結果。
在將其應用於你的代碼以前,應該瞭解兩個要點:
個人全部示例代碼都在GitHub上。