Golang sync 包的相關使用方法

2021-10-09 02:27:21 字數 3304 閱讀 7552

desc:go sync 包的使用方法,sync.mutex,sync.rmutex,sync.once,sync.cond,sync.waitgroup

儘管 golang 推薦通過 channel 進行通訊和同步,但在實際開發中 sync 包用得也非常的多。另外 sync 下還有乙個 atomic 包,提供了一些底層的原子操作(這裡不做介紹)。本篇文章主要介紹該包下的鎖的一些概念及使用方法。

整個包都圍繞這 locker 進行,這是乙個 inte***ce:

type locker inte***ce
只有兩個方法,lock()unlock()

另外該包下的物件,在使用過之後,千萬不要複製。

有許多同學不理解鎖的概念,下面會一一介紹到:

併發的情況下,多個執行緒或協程同時去修改乙個變數,可能會出現如下情況:

package main

import (

"fmt"

"sync"

"time"

)func main() (i)

}// 等待 1s 結束主程式

// 確保所有協程執行完

time.sleep(time.second)

}

觀察列印結果,是否出現 a 的值是相同的情況(未出現則重試或調大協程數),答案:是的。

顯然這不是我們想要的結果。出現這種情況的原因是,協程依次執行:從暫存器讀取 a 的值 -> 然後做加法運算 -> 最後寫會暫存器。試想,此時乙個協程取出 a 的值 3,正在做加法運算(還未寫回暫存器)。同時另乙個協程此時去取,取出了同樣的 a 的值 3。最終導致的結果是,兩個協程產出的結果相同,a 相當於只增加了 1。

所以,鎖的概念就是,我正在處理 a(鎖定),你們誰都別和我搶,等我處理完了(解鎖),你們再處理。這樣就實現了,同時處理 a 的協程只有乙個,就實現了同步。

把上面**裡的注釋取消掉再試下。

什麼是互斥鎖?它是鎖的一種具體實現,有兩個方法:

func (m *mutex) lock()

func (m *mutex) unlock()

在首次使用後不要複製該互斥鎖。對乙個未鎖定的互斥鎖解鎖將會產生執行時錯誤。

乙個互斥鎖只能同時被乙個 goroutine 鎖定,其它 goroutine 將阻塞直到互斥鎖被解鎖(重新爭搶對互斥鎖的鎖定)。

使用例子:

package main

import (

"fmt"

"sync"

"time"

)func main() , 2)

var l sync.mutex

go func() {}

}()go func() {}

}()// 等待 goroutine 執行結束

for i := 0; i < 2; i++

}

注意,平時所說的鎖定,其實就是去鎖定互斥鎖,而不是說去鎖定一段**。也就是說,當**執行到有鎖的地方時,它獲取不到互斥鎖的鎖定,會阻塞在那裡,從而達到控制同步的目的。

那麼什麼是讀寫鎖呢?它是針對讀寫操作的互斥鎖,讀寫鎖與互斥鎖最大的不同就是可以分別對進行鎖定。一般用在大量讀操作、少量寫操作的情況:

func (rw *rwmutex) lock()

func (rw *rwmutex) unlock()

func (rw *rwmutex) rlock()

func (rw *rwmutex) runlock()

由於這裡需要區分讀寫鎖定,我們這樣定義:

在首次使用之後,不要複製該讀寫鎖。不要混用鎖定和解鎖,如:lock 和 runlock、rlock 和 unlock。因為對未讀鎖定的讀寫鎖進行讀解鎖或對未寫鎖定的讀寫鎖進行寫解鎖將會引起執行時錯誤。

如何理解讀寫鎖呢?

同時只能有乙個 goroutine 能夠獲得寫鎖定。

同時可以有任意多個 gorouinte 獲得讀鎖定。

同時只能存在寫鎖定或讀鎖定(讀和寫互斥)。

也就是說,當有乙個 goroutine 獲得寫鎖定,其它無論是讀鎖定還是寫鎖定都將阻塞直到寫解鎖;當有乙個 goroutine 獲得讀鎖定,其它讀鎖定任然可以繼續;當有乙個或任意多個讀鎖定,寫鎖定將等待所有讀鎖定解鎖之後才能夠進行寫鎖定。所以說這裡的讀鎖定(rlock)目的其實是告訴寫鎖定:有很多人正在讀取資料,你給我站一邊去,等它們讀(讀解鎖)完你再來寫(寫鎖定)。

使用例子:

var count int

var rw sync.rwmutex

func (u *user) orgtest(ctx *gin.context) , 10)

for i := 0; i < 5; i++

for i := 0; i < 5; i++

for i := 0; i < 10; i++

}func read(n int, ch chan struct{}) {}

}func write(n int, ch chan struct{}) {}

}

waitgroup 用於等待一組 goroutine 結束,用法很簡單。它有三個方法:

func (wg *waitgroup) add(delta int)

func (wg *waitgroup) done()

func (wg *waitgroup) wait()

add 用來新增 goroutine 的個數。done 執行一次數量減 1。wait 用來等待結束:

使用例子:

func (u *user) orgtest(ctx *gin.context) (i)

}wg.wait()

fmt.println("所有 groutine 執行結束")

}

結果:

goroutine10 結束

goroutine1 結束

goroutine2 結束

goroutine3 結束

goroutine4 結束

goroutine5 結束

goroutine6 結束

goroutine7 結束

goroutine8 結束

goroutine9 結束

所有 groutine 執行結束

Unity Android互動 aar包的使用

上述部落格講解的很清楚,這裡不再贅述 現作以下補充 按照上述方法匯出的aar包包含unity的classes.jar每次使用壓縮軟體對其刪除比較麻煩,現提出一種不匯入classes.jar到aar的方法 build.gradle中 compile filetree include jar dir l...

python包使用 Python模組和包使用

1 什麼是模組 模組就是乙個.py的檔案 2 為什麼要使用模組?最開始的程式 沒有任何組織 函式 類 模組 包 為了讓程式的組織結構更加靈活清晰,降低耦合性 方便管理 3 如何使用模組 1 import 只能匯入在當前目錄 和內建的模組,使用模組裡的內容需要 模組.來呼叫 2 from.import...

go的相關包time os rand fmt

1 time包 2 time.time型別,用來表示時間 3 取當前時間,now time.now 4 time.now day time.now minute time.now month time.now year second now.unix 按秒計5 格式化,fmt.printf 02d ...