golang 基於共享變數的併發

2021-08-19 21:23:50 字數 2129 閱讀 9463

併發定義:當我們沒有辦法自信地確認乙個事件是在另乙個事件的前面或者後面發生的話,就說明x和y這兩個事件是併發的。

併發安全:如果其所有可訪問的方法和操作都是併發安全的話,那麼型別便是併發安全的。

競爭條件:程式在多個goroutine交叉執行操作時,沒有給出正確的結果。

只要有 兩個goroutine併發訪問

同一變數,且至

少其中的乙個是寫操作的時候就會發生資料競爭。

資料競爭會在兩個以上的goroutine併發訪問相同的變數且至少其中乙個為寫操作時發生。

第一種:不要去寫變數,變數直接提前初始化。

第二種:多個只允許乙個goroutine訪問變數,用select來監聽操作(go的金句:不要通過共享變數來通訊,通過通訊(channel)來共享變數)。

第三種:允許過個goroutine訪問變數,但是同一時間只允許乙個goroutine訪問。

現在我們來講第三種情況具體操作

golang 我們可以通過channel作為計量器,可以保證可以有多少個goroutine可以同時訪問。make(chan struct{},1),通過寫入讀取用阻塞的方式鎖定住指定的**塊的訪問。

var (

sema = make(chan struct{}, 1) // a binary semaphore guarding balance

balance int

)func deposit(amount int) {} // acquire token

balance = balance + amount

<-sema // release token

}func balance() int {} // acquire token

b := balance

<-sema // release token

return b

}

可以保證同一時刻只有乙個goroutine來訪問。

然而我們可以用sync包中的mutex來實現上面的功能,那就是:

互斥鎖 sync.mutex

互斥鎖:保證共享變數不會被併發訪問

import "sync"

var (

mu sync.mutex // guards balance

balance int

)func deposit(amount int)

func balance() int

在lock和unlock之間的**段中的內容goroutine可以隨便讀取或者修改,這個**段叫做臨界區。

注意:一定要釋放鎖(unlock),不管任何情況,可以利用defer mutex.unlock(),一定要注意go裡沒有重入鎖,如果遇到更小原子的操作,考慮分解成不帶鎖功能的小塊函式

接下來我們將另一種鎖:讀寫鎖sync.rwmutex

很多情況我們需要保證讀的效能,而互斥鎖會短暫的阻止其他的goroutine的執行,沒法達到很好的多併發效果(多讀單寫),這時讀寫鎖就可以很好的解決這個問題。

rlock()和runlock()獲取和釋放乙個讀取或者共享鎖。

rlock只能在臨界區共享變數沒有任何寫入操作時可用。一般來說,我們不應該假設邏輯上的

唯讀函式/方法也不會去更新某一些變數。如果沒法確定,那麼久使用互斥鎖(mutex)

最後我們來講下記憶體同步的問題

var x, y int

go func() ()

go func() ()

上面的例子:a1、a2、b1、b2 執行循序卻是毫無規律

在現代計算機中可能會有一堆處理器,每乙個都會有其本地快取(local cache)。為了效率,對記憶體的寫入一般會在每乙個處理器中緩衝,並在必要時一起flush到主存。這種情況下這些資料可能會以與當初goroutine寫入順序不同的順序被提交到主存。導致程式執行序列了,又同時序列的**訪問了共享變數,儘管goroutine a中一定需要觀察到x=1執行成功之後才會去讀取y,但它沒法確保自己觀察得到goroutine b中對y的寫入,所以a還可能會列印出y的乙個舊版的值。

有兩種方法解決:

1.變數限定在goroutine中使用,不訪問共享變數

2.用互斥條件訪問

golang 併發 共享資源安全

首先,我們需要知道 在golang中,多 goroutine 同時操作乙個共享資源時 我們需要保障資源的安全 我們對資源的操作結果要符合我們的預期 當我們未對資源做保護操作時,多個goroutine同時操作同一資源時,就可能會出現問題 例如 count 1 有a b兩個 goroutine 同時拿到...

Golang的併發安全

channel是go中代替共享記憶體的通訊方式,channel從底層實現上是一種佇列,在使用的時候需要通道的傳送方和接收方需要知道資料型別和具體通道。如果有一端沒有準備好或訊息沒有被處理會阻塞當前端。actor模型 在actor模型中,主角是actor,類似一種worker,actor彼此之間直接傳...

golang 併發鎖的陷阱

package main import sync strconv fmt type node struct var cache node func main cache 1 node wg sync.waitgroup for i 0 i 10000 i i wg.wait fmt.println ...