<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
反例如下,兩個Goroutine
分別讀寫。
func unsafeMap(){ var wg sync.WaitGroup m := make(map[int]int) wg.Add(2) go func() { defer wg.Done() for i := 0; i < 10000; i++ { m[i] = i } }() go func() { defer wg.Done() for i := 0; i < 10000; i++ { fmt.Println(m[i]) } }() wg.Wait() }
執行報錯:
0
fatal error: concurrent map read and map write
goroutine 7 [running]:
runtime.throw({0x10a76fa, 0x0})
......
使用並行安全的Map
func safeMap() { var wg sync.WaitGroup var m sync.Map wg.Add(2) go func() { defer wg.Done() for i := 0; i < 10000; i++ { m.Store(i, i) } }() go func() { defer wg.Done() for i := 0; i < 10000; i++ { fmt.Println(m.Load(i)) } }() wg.Wait() }
make
就能使用Store
、Load
、LoadOrStore
、Delete
、Range
等操作方法,自行體驗。很多場景下我們需要確保某些操作在高並行的場景下只執行一次,例如只載入一次組態檔、只關閉一次通道等。
init
函數是當所在的 package
首次被載入時執行,若遲遲未被使用,則既浪費了記憶體,又延長了程式載入時間。
sync.Once
可以在程式碼的任意位置初始化和呼叫,因此可以延遲到使用時再執行,並行場景下是執行緒安全的。
在多數情況下,sync.Once
被用於控制變數的初始化,這個變數的讀寫滿足如下三個條件:
var loadOnce sync.Once var x int for i:=0;i<10;i++{ loadOnce.Do(func() { x++ }) } fmt.Println(x)
輸出
1
sync.Cond
基於互斥鎖/讀寫鎖,它和互斥鎖的區別是什麼呢?
互斥鎖 sync.Mutex
通常用來保護臨界區和共用資源,條件變數 sync.Cond
用來協調想要存取共用資源的 goroutine
。
也就是在存在共用變數時,可以直接使用sync.Cond
來協調共用變數,比如最常見的共用佇列,多消費多生產的模式。
我一開始也很疑惑為什麼不使用channel
和select
的模式來做生產者消費者模型(實際上也可以),這一節不是重點就不展開討論了。
建立範例
func NewCond(l Locker) *Cond
NewCond
建立 Cond
範例時,需要關聯一個鎖。
廣播喚醒所有
func (c *Cond) Broadcast()
Broadcast
喚醒所有等待條件變數 c
的 goroutine
,無需鎖保護。
喚醒一個協程
func (c *Cond) Signal()
Signal
只喚醒任意 1 個等待條件變數 c
的 goroutine
,無需鎖保護。
等待
func (c *Cond) Wait()
每個 Cond 範例都會關聯一個鎖 L(互斥鎖 *Mutex,或讀寫鎖 *RWMutex),當修改條件或者呼叫 Wait 方法時,必須加鎖。
舉個不恰當的例子,實現一個經典的生產者和消費者模式,但有先決條件:
var ( cnt int shuttingDown = false cond = sync.NewCond(&sync.Mutex{}) )
cnt
為佇列,這裡直接用變數代替了,變數就是佇列長度。shuttingDown
消費關閉狀態。cond
現成的佇列控制。生產者
func Add(entry int) { cond.L.Lock() defer cond.L.Unlock() cnt += entry fmt.Println("生產咯,來消費吧") cond.Signal() }
消費者
func Get() (int, bool) { cond.L.Lock() defer cond.L.Unlock() for cnt == 0 && !shuttingDown { fmt.Println("未關閉但空了,等待生產") cond.Wait() } if cnt == 0 { fmt.Println("關閉咯,也消費完咯") return 0, true } cnt-- return 1, false }
關閉程式
func Shutdown() { cond.L.Lock() defer cond.L.Unlock() shuttingDown = true fmt.Println("要關閉咯,大家快消費") cond.Broadcast() }
主程式
var wg sync.WaitGroup wg.Add(2) time.Sleep(time.Second) go func() { defer wg.Done() for i := 0; i < 10; i++ { go Add(1) if i%5 == 0 { time.Sleep(time.Second) } } }() go func() { defer wg.Done() shuttingDown := false for !shuttingDown { var cur int cur, shuttingDown = Get() fmt.Printf("當前消費 %d, 佇列剩餘 %d n", cur, cnt) } }() time.Sleep(time.Second * 5) Shutdown() wg.Wait()
輸出
生產咯,來消費吧
當前消費 1, 佇列剩餘 0
未關閉但空了,等待生產
生產咯,來消費吧
生產咯,來消費吧
當前消費 1, 佇列剩餘 1
當前消費 1, 佇列剩餘 0
未關閉但空了,等待生產
生產咯,來消費吧
生產咯,來消費吧
生產咯,來消費吧
當前消費 1, 佇列剩餘 2
當前消費 1, 佇列剩餘 1
當前消費 1, 佇列剩餘 0
未關閉但空了,等待生產
生產咯,來消費吧
生產咯,來消費吧
生產咯,來消費吧
生產咯,來消費吧
當前消費 1, 佇列剩餘 1
當前消費 1, 佇列剩餘 2
當前消費 1, 佇列剩餘 1
當前消費 1, 佇列剩餘 0
未關閉但空了,等待生產
要關閉咯,大家快消費
關閉咯,也消費完咯
當前消費 0, 佇列剩餘 0
1.sync.Map 並行安全的Map。
2.sync.Once 只執行一次,適用於設定讀取、通道關閉。
3.sync.Cond 控制協調共用資源。
以上就是GO語言並行之好用的sync包詳解的詳細內容,更多關於GO語言 sync包的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45