成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

The Go Memory Model / Happens Before 是什么?

開發(fā) 前端
“Happens Before”是 Go 內(nèi)存模型中用以描述不同 goroutine 中操作之間可見性順序的核心概念。簡單來說,如果事件 A “happens before” 事件 B,那么事件 A 的結(jié)果保證對事件 B 可見。這種關(guān)系是傳遞的:如果 A happens before B,且 B happens before C,那么 A happens before C。

Happens Before (先行發(fā)生)

“Happens Before”是 Go 內(nèi)存模型中用以描述不同 goroutine 中操作之間可見性順序的核心概念。簡單來說,如果事件 A “happens before” 事件 B,那么事件 A 的結(jié)果保證對事件 B 可見。這種關(guān)系是傳遞的:如果 A happens before B,且 B happens before C,那么 A happens before C。

“Happens Before”關(guān)系主要由以下兩種情況構(gòu)成:

  1. Sequenced Before (順序先于)
  • 定義 :在單個(gè) goroutine 內(nèi)部,操作的執(zhí)行順序遵循代碼中語句的順序。例如,在 x = 1; y = x + 1 中,對 x 的賦值操作順序先于對 y 的賦值操作。
  • 作用 :這是最直觀的排序,保證了單個(gè) goroutine 內(nèi)代碼的邏輯按預(yù)期執(zhí)行。
  1. Synchronized Before (同步先于)
  • 定義 :當(dāng)不同的 goroutine 通過同步原語(如通道操作、互斥鎖等)進(jìn)行交互時(shí),這些原語會(huì)建立起 goroutine 間的同步關(guān)系。例如,對一個(gè)通道的發(fā)送操作,如果成功匹配到接收操作,那么發(fā)送完成“同步先于”接收完成。
  • 作用 :這是跨 goroutine 保證內(nèi)存可見性的關(guān)鍵。同步操作不僅協(xié)調(diào)執(zhí)行,還確保一個(gè) goroutine 中的寫操作對另一個(gè) goroutine 中的后續(xù)讀操作可見。

Happens Before = Sequenced Before ∪ Synchronized Before (取傳遞閉包)

最終的“Happens Before”關(guān)系是“順序先于”和“同步先于”關(guān)系的并集的傳遞閉包。這意味著,一系列操作,即使跨越多個(gè) goroutine,只要它們能通過“順序先于”和“同步先于”鏈接起來,就能形成一個(gè)“Happens Before”鏈條。

為什么重要?

對于一個(gè)普通的(非同步的)內(nèi)存讀取操作 r,如果要保證它能觀察到某個(gè)寫入操作 w 的值,必須滿足:

  1. w happens before r.
  2. 沒有其他的寫入操作 w' (針對同一內(nèi)存位置) 滿足 w happens before w' 且 w' happens before r。

如果一個(gè)程序沒有數(shù)據(jù)競爭(Data Race-Free, DRF),即所有對共享變量的并發(fā)訪問都通過同步原語進(jìn)行了保護(hù),那么該程序的執(zhí)行就如同所有 goroutine 的操作被以某種順序交錯(cuò)在一個(gè)單一處理器上執(zhí)行一樣,這被稱為“順序一致性”(Sequentially Consistent, DRF-SC)。

通道通信的同步細(xì)節(jié) (Channel Communication Synchronization Details)

通道是 Go 中主要的 goroutine 間同步機(jī)制。每一次在特定通道上的發(fā)送操作都會(huì)與該通道上相應(yīng)的接收操作相匹配。

以下是文檔中提到的關(guān)于通道通信建立的“Synchronized Before”關(guān)系的具體規(guī)則:

  1. “A send on a channel is synchronized before the completion of the corresponding receive from that channel.”
  • 中文 :對一個(gè)通道的發(fā)送操作,同步先于 (happens before) 從該通道完成的相應(yīng)接收操作。
  • 解釋 :這條規(guī)則是最基礎(chǔ)的。無論通道是帶緩沖的還是不帶緩沖的,一旦一個(gè)值被成功發(fā)送,并且這個(gè)值被接收方成功接收,那么發(fā)送這個(gè)動(dòng)作(及其之前的所有在同一 goroutine 中的操作)對于接收完成這個(gè)動(dòng)作(及其之后的所有在同一 goroutine 中的操作)是可見的。
  • 例子
var c = make(chan int, 10) // 可以是帶緩沖或不帶緩沖
var a string

func f() {
    a = "hello, world" // (1) 對 a 的寫操作
    c <- 0             // (2) 對 c 的發(fā)送操作
}

func main() {
    go f()
    <-c                // (3) 從 c 的接收操作
    print(a)           // (4) 對 a 的讀操作
}

在這個(gè)例子中:

  • (1) 順序先于 (2) (在 goroutine f 內(nèi)部)。
  • 根據(jù)本條規(guī)則,(2) (發(fā)送) 同步先于 (3) (接收完成)。
  • (3) 順序先于 (4) (在 goroutine main 內(nèi)部)。
  • 因此,通過傳遞性,對 a 的寫操作 (1) happens before 對 a 的讀操作 (4)。所以程序保證打印出 "hello, world"。
  1. “The closing of a channel is synchronized before a receive that returns a zero value because the channel is closed.”
  • 中文 :關(guān)閉一個(gè)通道的操作,同步先于 (happens before) 因通道已關(guān)閉而返回零值的接收操作。
  • 解釋 :當(dāng)一個(gè)通道被關(guān)閉后,任何后續(xù)的接收操作會(huì)立即返回一個(gè)該通道類型的零值,并且第二個(gè)返回值 (通常是 ok) 會(huì)是 false。這個(gè)規(guī)則保證,關(guān)閉通道的動(dòng)作(及其之前的所有操作)對于那個(gè)感知到通道已關(guān)閉的接收操作是可見的。
  • 例子 :如果將上一個(gè)例子中的 c <- 0 替換為 close(c),行為保證是相同的。main 中的 <-c 會(huì)因?yàn)橥ǖ狸P(guān)閉而返回 (對于 int 類型是 0),print(a) 仍然會(huì)打印 "hello, world"。
  1. “A receive from an unbuffered channel is synchronized before the completion of the corresponding send on that channel.”
  • 中文 :從一個(gè)無緩沖通道的接收操作,同步先于 (happens before) 在該通道上完成的相應(yīng)發(fā)送操作。
  • 解釋 :這條規(guī)則特定于 無緩沖通道 。無緩沖通道的發(fā)送和接收是同步的,發(fā)送方會(huì)阻塞直到接收方準(zhǔn)備好接收,接收方也會(huì)阻塞直到發(fā)送方準(zhǔn)備好發(fā)送。這條規(guī)則意味著,接收方goroutine中,接收操作完成前的所有操作,對于發(fā)送方goroutine中,發(fā)送操作完成后的所有操作,是可見的。這與第一條規(guī)則方向相反,共同確立了無緩沖通道的“會(huì)合點(diǎn)”(rendezvous)特性。
  • 例子
var c = make(chan int) // 無緩沖通道
var a string

func f() {
    a = "hello, world" // (1) 對 a 的寫操作
    <-c                // (2) 從 c 的接收操作
}

func main() {
    go f()
    c <- 0             // (3) 對 c 的發(fā)送操作
    print(a)           // (4) 對 a 的讀操作
}

在這個(gè)例子中:

  • (1) 順序先于 (2) (在 goroutine f 內(nèi)部)。
  • 根據(jù)本條規(guī)則,(2) (接收) 同步先于 (3) (發(fā)送完成)。
  • (3) 順序先于 (4) (在 goroutine main 內(nèi)部)。
  • 因此,對 a 的寫操作 (1) happens before 對 a 的讀操作 (4)。程序同樣保證打印 "hello, world"。
  • 注意 :如果 c 是一個(gè)帶緩沖通道 (例如 make(chan int, 1)),這個(gè)程序就不能保證打印 "hello, world"。因?yàn)榘l(fā)送操作 (3) 可能在 f 中的接收操作 (2) 執(zhí)行之前就完成了(如果緩沖區(qū)未滿),這樣就不會(huì)建立 (2) 同步先于 (3) 的關(guān)系。
  1. “The k-th receive on a channel with capacity C is synchronized before the completion of the k+C-th send from that channel completes.”
  • 中文 :對于一個(gè)容量為 C 的通道,第 k 個(gè)接收操作,同步先于 (happens before) 該通道上的第 k+C 個(gè)發(fā)送操作的完成。
  • 解釋 :這條規(guī)則是針對 帶緩沖通道 的,它推廣了無緩沖通道的規(guī)則,并允許使用帶緩沖通道來建模計(jì)數(shù)信號量。可以這樣理解:當(dāng)通道滿了(即已經(jīng)有 C 個(gè)元素在緩沖中,等待被接收),下一個(gè)(即第 C+1 個(gè))發(fā)送操作必須等待通道中至少有一個(gè)元素被接收出去后才能完成。更一般地,第 k+C 個(gè)發(fā)送者必須等待第 k 個(gè)接收者完成后才能繼續(xù)。
  • 作用 :這允許我們限制并發(fā)數(shù)量。通道中的元素?cái)?shù)量代表活躍的“許可”,通道的容量代表最大并發(fā)數(shù)。發(fā)送操作獲取許可,接收操作釋放許可。
  • 例子
var limit = make(chan int, 3) // 容量 C = 3

func main() {
    // 假設(shè) work 是一個(gè)包含多個(gè)待執(zhí)行任務(wù)的切片
    for _, w := range work {
        go func(job func()) {
            limit <- 1   // (發(fā)送) 獲取一個(gè)許可。如果 limit 已滿 (3個(gè)goroutine已獲取),這里會(huì)阻塞
            job()        // 執(zhí)行任務(wù)
            <-limit      // (接收) 釋放一個(gè)許可
        }(w)
    }
    select{} // 保持 main goroutine 存活
}

在這個(gè)例子中,limit 通道確保最多只有3個(gè) job 同時(shí)運(yùn)行。

  • 當(dāng)?shù)?, 2, 3個(gè) goroutine 執(zhí)行 limit <- 1 (發(fā)送) 時(shí),它們都能成功并將元素放入通道。
  • 當(dāng)?shù)?個(gè) goroutine 嘗試執(zhí)行 limit <- 1 (第4次發(fā)送) 時(shí),由于通道已滿 (3個(gè)元素),它會(huì)阻塞。
  • 這符合規(guī)則:第1個(gè)接收 (k=1) 必須發(fā)生在第 1+3=4 個(gè)發(fā)送完成之前。也就是說,只有當(dāng)最早獲取許可的3個(gè) goroutine 中的某一個(gè)完成了它的 job() 并執(zhí)行了 <-limit (第1次接收),釋放了一個(gè)位置后,第4個(gè) goroutine 的 limit <- 1 (第4次發(fā)送) 才能成功。

總結(jié)一下,通道的這些同步規(guī)則是 Go 并發(fā)編程中正確性的基石。通過理解并正確使用這些規(guī)則,開發(fā)者可以構(gòu)建出沒有數(shù)據(jù)競爭且行為可預(yù)測的并發(fā)程序。這些規(guī)則定義了明確的“Happens Before”邊界,從而保證了內(nèi)存操作的可見性。

數(shù)據(jù)競爭的處理方式

  • 精華 :Go明確定義了數(shù)據(jù)競爭(data race),即多個(gè)goroutine同時(shí)訪問同一內(nèi)存位置且至少有一個(gè)是寫操作,且沒有同步保護(hù)。不同于C/C++的未定義行為,Go在檢測到數(shù)據(jù)競爭時(shí)可能會(huì)報(bào)告并終止程序,或者允許讀取并發(fā)寫入的值,但結(jié)果是有限的。
  • 為什么不容易注意到 :您可能習(xí)慣于通過go build -race檢測數(shù)據(jù)競爭,但對Go在數(shù)據(jù)競爭下的具體行為(例如不會(huì)像C/C++那樣徹底不可預(yù)測)缺乏深入思考。
  • 值得學(xué)習(xí) :理解Go對數(shù)據(jù)競爭的處理方式,可以幫助您更好地調(diào)試程序,避免依賴未定義行為的假設(shè)。此外,這也強(qiáng)化了Go鼓勵(lì)使用同步機(jī)制的哲學(xué),對比C/C++的差異能讓您更欣賞Go的設(shè)計(jì)。

不正確同步的示例與陷阱

  • 精華 :文檔列舉了幾個(gè)常見的錯(cuò)誤同步模式,例如
var a string
var done bool

func setup() {
    a = "hello, world"
    done = true
}

func doprint() {
    if !done {
        once.Do(setup)
    }
    print(a)
}

func twoprint() {
    go doprint()
    go doprint()
}

雙重檢查鎖定(Double-Checked Locking) :but there is no guarantee that, in doprint, observing the write to done implies observing the write to a. This version can (incorrectly) print an empty string instead of "hello, world".

var a string
var done bool

func setup() {
    a = "hello, world"
    done = true
}

func main() {
    go setup()
    for !done {
    }
    print(a)
}

忙等待(Busy Waiting) :As before, there is no guarantee that, in main, observing the write to done implies observing the write to a, so this program could print an empty string too. Worse, there is no guarantee that the write to done will ever be observed by main, since there are no synchronization events between the two threads. The loop in main is not guaranteed to finish.

  • 為什么不容易注意到 :這些錯(cuò)誤模式在單線程邏輯中看似合理,但在并發(fā)環(huán)境下會(huì)失效。有經(jīng)驗(yàn)的開發(fā)者可能偶爾依賴這些“巧妙”的方法,而未意識到它們的風(fēng)險(xiǎn)。
  • 值得學(xué)習(xí) :通過研究這些反例,您可以避免在代碼中犯類似錯(cuò)誤。例如,解決這些問題的正確方法是顯式同步(如使用鎖或通道),這能顯著提高代碼的健壯性。

編譯器優(yōu)化的限制

  • 精華:Go內(nèi)存模型對編譯器優(yōu)化施加了嚴(yán)格限制,以確保并發(fā)程序的正確性。例如

編譯器不能將寫操作移出條件語句

不能假設(shè)循環(huán)會(huì)終止或函數(shù)會(huì)返回,以避免引入意外的內(nèi)存訪問

單次讀操作不能觀察到多個(gè)值,單次寫操作不能寫入多個(gè)值

  • 為什么不容易注意到 :這些限制主要影響底層編譯器行為,作為應(yīng)用開發(fā)者,您可能很少直接接觸。但它們間接決定了您的代碼在并發(fā)環(huán)境下的表現(xiàn)。
  • 值得學(xué)習(xí) :理解這些限制能幫助您在編寫高性能代碼時(shí),預(yù)判哪些優(yōu)化是安全的。例如,知道編譯器不會(huì)重新加載共享變量,可以避免在復(fù)雜邏輯中意外丟失同步保護(hù)。

通道通信的同步細(xì)節(jié)

  • 精華:文檔詳細(xì)描述了通道的同步行為:

無緩沖通道的接收在發(fā)送完成之前“happens before”發(fā)送完成。

緩沖通道的第 k 次接收在第 k+C 次發(fā)送完成之前“happens before”發(fā)送完成(C為通道容量)。

關(guān)閉通道在接收到零值之前“happens before”。

  • 為什么不容易注意到 :您可能已經(jīng)熟練使用通道,但對緩沖與無緩沖通道的同步差異、以及關(guān)閉通道的精確行為關(guān)注不夠。
  • 值得學(xué)習(xí) :掌握這些細(xì)節(jié)能幫助您在設(shè)計(jì)并發(fā)模式時(shí)(如信號量、限流)更精準(zhǔn)地控制goroutine間的同步。例如,理解緩沖通道的同步規(guī)則,可以避免因容量誤判導(dǎo)致的死鎖或數(shù)據(jù)丟失。

原子操作的同步能力

  • 精華 :sync/atomic包中的原子操作(如AddInt32、CompareAndSwap)不僅提供無鎖操作,還能建立goroutine間的同步關(guān)系。所有原子操作表現(xiàn)得像在一個(gè)順序一致的順序中執(zhí)行。
  • 為什么不容易注意到 :原子操作常被視為性能優(yōu)化工具,而其同步能力可能被忽視。
  • 值得學(xué)習(xí) :在需要輕量級同步的場景下,正確使用原子操作可以替代鎖,減少開銷。例如,理解原子操作的“happens before”關(guān)系,可以在高并發(fā)計(jì)數(shù)器或狀態(tài)標(biāo)志中確保一致性。

Finalizers的同步行為

  • 精華 :runtime.SetFinalizer(x, f)在finalizer f(x)調(diào)用之前“happens before”,這是垃圾回收前清理資源的高級機(jī)制。
  • 為什么不容易注意到 :finalizers是Go中的高級特性,日常開發(fā)中用得不多,且其同步細(xì)節(jié)容易被忽略。
  • 值得學(xué)習(xí) :如果您需要在并發(fā)環(huán)境中管理資源(如文件句柄、網(wǎng)絡(luò)連接),理解finalizers的同步行為能幫助您正確實(shí)現(xiàn)清理邏輯,避免資源泄露或競爭問題。
責(zé)任編輯:武曉燕 來源: Piper蛋窩
相關(guān)推薦

2021-07-29 07:51:43

工具 HappensBefore

2021-08-11 11:25:22

happens - bJava代碼

2022-06-27 08:01:45

Java內(nèi)存模型

2020-05-28 07:50:18

重排序happens-befCPU

2022-06-08 13:54:23

指令重排Java

2021-05-09 18:32:05

JMMHappens-befJava

2021-12-03 18:29:31

GoAny 泛型

2022-08-17 17:57:37

GoGo語言

2024-01-23 11:31:24

模型AI

2021-10-29 10:55:07

Go 泛型語言

2021-03-05 08:51:00

Go語言make

2024-09-02 00:30:41

Go語言場景

2021-10-10 19:28:00

Go對象選擇器

2021-11-15 06:56:46

Go語言Tag

2021-12-27 18:27:18

GoTryLockJava

2017-03-21 23:29:44

DevOps運(yùn)維開發(fā)

2021-12-21 08:51:13

Go數(shù)據(jù)Model

2023-09-26 13:33:27

AI自動(dòng)駕駛

2009-07-07 16:50:39

ServletResp

2009-09-16 09:39:50

ccna是什么CCNA
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 91av在线视频观看 | 欧美三级电影在线播放 | 亚洲精品在线视频 | 天堂久久网| 欧美乱大交xxxxx另类电影 | 日韩在线视频观看 | 国产日产久久高清欧美一区 | 天堂综合 | 91久久综合亚洲鲁鲁五月天 | 伦理片97 | 欧美在线日韩 | 国产午夜精品一区二区三区嫩草 | 久久久久国产一区二区三区 | 亚洲欧美在线一区 | aa级毛片毛片免费观看久 | 日韩在线视频一区 | 色一情一乱一伦一区二区三区 | 欧美性久久 | 亚洲不卡在线观看 | 男女羞羞视频免费看 | 欧美大片一区二区 | 亚洲成人99 | 国产一区二区在线播放视频 | 欧美日韩一区二区视频在线观看 | 欧美精品欧美精品系列 | 99久久99 | 91成人精品视频 | 国产一区二区三区视频免费观看 | 黄色操视频| 国产精品久久久久久亚洲调教 | 亚洲精品在线视频 | 成人午夜网| 久久亚洲一区 | 九九热精品免费 | 国产欧美一区二区久久性色99 | 国产精品美女一区二区三区 | 黄色大片免费网站 | 美女久久 | 国产精品美女 | 国产精品久久久久久久久久久久冷 | 亚洲草草视频 |