Go語言實戰筆記(十三) | Go 并發資源競爭

      網友投稿 681 2025-04-02

      《Go語言實戰》讀書筆記,未完待續,歡迎掃碼關注公眾號flysnow_org或者網站http://www.flysnow.org/,第一時間看后續筆記。覺得有幫助的話,順手分享到朋友圈吧,感謝支持。 有并發,就有資源競爭,如果兩個或者多個goroutine在沒有相互同步的情況下,訪問某個共享的資源,比如同時對該資源進行讀寫時,就會處于相互競爭的狀態,這就是并發中的資源競爭。


      并發本身并不復雜,但是因為有了資源競爭的問題,就使得我們開發出好的并發程序變得復雜起來,因為會引起很多莫名其妙的問題。

      這是一個資源競爭的例子,我們可以多運行幾次這個程序,會發現結果可能是2,也可以是3,也可能是4。因為共享資源count變量沒有任何同步保護,所以兩個goroutine都會對其進行讀寫,會導致對已經計算好的結果覆蓋,以至于產生錯誤結果,這里我們演示一種可能,兩個goroutine我們暫時稱之為g1和g2。

      g1讀取到count為0。

      然后g1暫停了,切換到g2運行,g2讀取到count也為0。

      g2暫停,切換到g1,g1對count+1,count變為1。

      g1暫停,切換到g2,g2剛剛已經獲取到值0,對其+1,最后賦值給count還是1

      《Go語言實戰》筆記(十三) | Go 并發資源競爭

      有沒有注意到,剛剛g1對count+1的結果被g2給覆蓋了,兩個goroutine都+1還是1

      不再繼續演示下去了,到這里結果已經錯了,兩個goroutine相互覆蓋結果。我們這里的runtime.Gosched()是讓當前goroutine暫停的意思,退回執行隊列,讓其他等待的goroutine運行,目的是讓我們演示資源競爭的結果更明顯。注意,這里還會牽涉到CPU問題,多核會并行,那么資源競爭的效果更明顯。

      所以我們對于同一個資源的讀寫必須是原子化的,也就是說,同一時間只能有一個goroutine對共享資源進行讀寫操作。

      共享資源競爭的問題,非常復雜,并且難以察覺,好在Go為我們提供了一個工具幫助我們檢查,這個就是go build -race命令。我們在當前項目目錄下執行這個命令,生成一個可以執行文件,然后再運行這個可執行文件,就可以看到打印出的檢測信息。

      多加了一個-race標志,這樣生成的可執行程序就自帶了檢測資源競爭的功能,下面我們運行,也是在終端運行。

      我這里示例生成的可執行文件名是hello,所以是這么運行的,這時候,我們看終端輸出的檢測結果。

      看,找到一個資源競爭,連在那一行代碼出了問題,都標示出來了。goroutine 7在代碼25行讀取共享資源value := count,而這時goroutine 6正在代碼28行修改共享資源count = value,而這兩個goroutine都是從main函數啟動的,在16、17行,通過go關鍵字。

      既然我們已經知道共享資源競爭的問題,是因為同時有兩個或者多個goroutine對其進行了讀寫,那么我們只要保證,同時只有一個goroutine讀寫不就可以了,現在我們就看下傳統解決資源競爭的辦法--對資源加鎖。

      Go語言提供了atomic包和sync包里的一些函數對共享資源同步枷鎖,我們先看下atomic包。

      留意這里atomic.LoadInt32和atomic.StoreInt32兩個函數,一個讀取int32類型變量的值,一個是修改int32類型變量的值,這兩個都是原子性的操作,Go已經幫助我們在底層使用加鎖機制,保證了共享資源的同步和安全,所以我們可以得到正確的結果,這時候我們再使用資源競爭檢測工具go build -race檢查,也不會提示有問題了。

      atomic包里還有很多原子化的函數可以保證并發下資源同步訪問修改的問題,比如函數atomic.AddInt32可以直接對一個int32類型的變量進行修改,在原值的基礎上再增加多少的功能,也是原子性的,這里不再舉例,大家自己可以試試。

      atomic雖然可以解決資源競爭問題,但是比較都是比較簡單的,支持的數據類型也有限,所以Go語言還提供了一個sync包,這個sync包里提供了一種互斥型的鎖,可以讓我們自己靈活的控制哪些代碼,同時只能有一個goroutine訪問,被sync互斥鎖控制的這段代碼范圍,被稱之為臨界區,臨界區的代碼,同一時間,只能又一個goroutine訪問。剛剛那個例子,我們還可以這么改造。

      實例中,新聲明了一個互斥鎖mutex sync.Mutex,這個互斥鎖有兩個方法,一個是mutex.Lock(),一個是mutex.Unlock(),這兩個之間的區域就是臨界區,臨界區的代碼是安全的。

      示例中我們先調用mutex.Lock()對有競爭資源的代碼加鎖,這樣當一個goroutine進入這個區域的時候,其他goroutine就進不來了,只能等待,一直到調用mutex.Unlock()?釋放這個鎖為止。

      這種方式比較靈活,可以讓代碼編寫者任意定義需要保護的代碼范圍,也就是臨界區。除了原子函數和互斥鎖,Go還為我們提供了更容易在多個goroutine同步的功能,這就是通道chan,我們下篇講。

      《Go語言實戰》讀書筆記,未完待續,歡迎掃碼關注公眾號flysnow_org或者網站http://www.flysnow.org/,第一時間看后續筆記。覺得有幫助的話,順手分享到朋友圈吧,感謝支持。

      本文轉載自異步社區。

      軟件開發 編程語言

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:怎么分析數據并在線制作漏斗圖?使用這款工具輕松做到
      下一篇:2016wps有刪除背景的功能嗎(word2016刪除背景)
      相關文章
      国产亚洲成AV人片在线观黄桃| 亚洲一区二区三区AV无码| 亚洲狠狠久久综合一区77777| 亚洲欧洲精品成人久久奇米网| 精品亚洲国产成人av| 亚洲色在线无码国产精品不卡| 亚洲一区二区三区写真| 亚洲一区中文字幕在线观看| 亚洲国产成+人+综合| 亚洲精彩视频在线观看| 亚洲欧洲中文日产| 亚洲依依成人精品| 亚洲乱码在线观看| 亚洲精品色播一区二区| 成人精品国产亚洲欧洲| 亚洲 自拍 另类小说综合图区| 亚洲成av人片不卡无码久久| 亚洲综合国产精品第一页| 亚洲国产精品丝袜在线观看| 亚洲色一色噜一噜噜噜| 久久亚洲色一区二区三区| 亚洲色偷拍另类无码专区| 日韩亚洲人成在线综合日本| 亚洲国产高清视频| 久久久久亚洲精品日久生情 | 亚洲欧洲国产视频| 激情五月亚洲色图| 亚洲人成电影网站免费| 精品韩国亚洲av无码不卡区| 亚洲人成色77777在线观看大| 亚洲精品无码久久久久sm| 亚洲av日韩av激情亚洲| 亚洲精品中文字幕乱码影院| 亚洲日本乱码卡2卡3卡新区| 亚洲精品国产av成拍色拍| 国产亚洲福利精品一区二区| 国产a v无码专区亚洲av| 亚洲AV无码一区东京热久久| 久久亚洲AV无码精品色午夜麻豆| 国产精品亚洲精品青青青| 校园亚洲春色另类小说合集 |