Golang Memory Model
TODO:
建議
如何保證在一個 goroutine 中看到在另一個 goroutine 修改的變數的值,如果程序中修改數據時有其他 goroutine 同時讀取, 那麼必須將讀取串行化。 為了串行化訪問,請使用 channel 或其他同步原語,例如 sync 和 sync/atomic 來保護數據
先行發生 (Happen Before)
在一個gouroutine中,讀和寫一定是按照程序中的順序執行的。 即編譯器和處理器只有在不會改變這個goroutine的行為時才可能修改讀和寫的執行順序。 由於重排,不同的goroutine可能會看到不同的執行順序。 例如: 一個goroutine執行 a=1; b=2, 另一個 goroutine 可能看到 b 在 a 之前更新。
var a, b int
func f() {
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
go f()
g()
}
it can happen that g prints 2 and then 0.
happens-before有什麼用呢?它可以用來幫助我們釐清兩個並發讀寫之間的關係。 對於並發讀寫問題,我們最關心的經常是reader是否能準確觀察到writer寫入的值。 happens-before正是為這個問題設計的,具體來說,要想讓某次讀取r準確觀察到某次寫入w,只需滿足:
- w happens-before r;
- 對變量的其它寫入w1,要麼 w1 happens-before w,要麼 r happens-before w1;簡單理解就是沒有其它寫入覆蓋這次寫入;
The happens before relation is defined as the transitive closure of the union of the sequenced before and synchronized before relations. Requirement 3: For an ordinary (non-synchronizing) data read r on a memory location x, W(r) must be a write w that is visible to r, where visible means that both of the following hold:
- w happens before r.
- w does not happen before any other write w' (to x) that happens before r.
Memory Rordering and Memory Barrier
原子值複製
一旦atomic.Value類型的值,就是原子值被真正使用,它就不應該再被複製了。 只要用它來存儲值了,就相當於開始真正使用了。 atomic.Value類型屬於結構體類型,而結構體類型屬於值類型。 所以,複製該類型的值會產生一個完全分離的新值。這個新值相當於被複製的那個值的一個快照。 之後,不論後者存儲的值怎樣改變,都不會影響到前者的使用,反之亦然。 https://go.dev/play/p/Wua238yxLoJ
func main() {
var box atomic.Value
box2 := box // 原子值真正使用之前可以被複製
v1 := [...]int{1,2,3}
box.Store(v1) // 對box1的改變,不會影響到box2
fmt.Println(box.Load()) // [1 2 3]
fmt.Println(box2.Load()) // nil
}