Go?為什么不支持可重入鎖原理解析
引言
程序里的鎖,是很多小伙伴在寫分布式應用時用的最多的一個利器之一。
使用 Go 的同學里,絕大部分都有其他語言的經驗,就會對其中一點有疑惑,那就是 Go 里的鎖,竟然不支持可重入?
為此,今天煎魚帶大家一起來了解這里的設計考量,看看為什么。
可重入鎖
如果對已經上鎖的普通互斥鎖進行 “加鎖” 操作,其結果要么失敗,要么會阻塞至解鎖。
鎖的場景如下:
- 在加鎖上:如果是可重入互斥鎖,當前嘗試加鎖的線程如果就是持有該鎖的線程時,加鎖操作就會成功。
- 在解鎖上:可重入互斥鎖一般都會記錄被加鎖的次數,只有執(zhí)行相同次數的解鎖操作才會真正解鎖。
簡單來講,可重入互斥鎖是互斥鎖的一種,同一線程對其多次加鎖不會產生死鎖,又或是導致阻塞。
不同語言間實現可能或多或少有些區(qū)別,但大體意思差不多。
請你想一下,Go 是怎么樣的呢?
Go 支持情況
我們看到以下這個 Go 互斥鎖例子:
var mu sync.Mutex
func main() {
mu.Lock()
mu.Lock()
}這段 Go 程序會阻塞嗎?不會,會報以下錯誤:
fatal error: all goroutines are asleep - deadlock!
Go 顯然是不支持可重入互斥鎖的。
官方回復
Go 設計原則
在工程中使用互斥的根本原因是:為了保護不變量,也可以用于保護內、外部的不變量。
基于此,Go 在互斥鎖設計上會遵守這幾個原則。如下:
- 在調用
mutex.Lock方法時,要保證這些變量的不變性保持,不會在后續(xù)的過程中被破壞。 在調用
mu.Unlock方法時,要保證:- 程序不再需要依賴那些不變量。
- 如果程序在互斥鎖加鎖期間破壞了它們,則需要確保已經恢復了它們。
不支持的原因
講了 Go 自己的設計原則后,那為什么不支持可重入呢?
其實 Russ Cox 于 2010 年在《Experimenting with GO》就給出了答復,認為遞歸(又稱:重入)互斥是個壞主意,這個設計并不好。
我們可以結合官方的例子來理解。
如下:
func F() {
mu.Lock()
... do some stuff ...
G()
... do some more stuff ...
mu.Unlock()
}
func G() {
mu.Lock()
... do some stuff ...
mu.Unlock()
}在上述代碼中,我們在 F 方法中調用 mu.Lock 方法加上了鎖。如果支持可重入鎖,接著就會進入到 G 方法中。
此時就會有一個致命的問題,你不知道 F 和 G 方法加鎖后是不是做了什么事情,從而導致破壞了不變量,畢竟隨手起幾個協(xié)程做點壞事,也是完全可能的。
這對于 Go 是無法接受的,可重入的設計違反了前面所提到的設計理念,也就是:“要保證這些變量的不變性保持,不會在后續(xù)的過程中被破壞”。
基于上述原因,Go 官方團隊選擇了沒有支持該項特性。
總結
Go 互斥鎖沒有支持可重入鎖的設計,也是喜歡的大道至簡的思路了,可能的干擾比較多,不如直接簡單的來。
以上就是Go 為什么不支持可重入鎖原理解析的詳細內容,更多關于Go不支持可重入鎖的資料請關注腳本之家其它相關文章!
相關文章
Go處理json數據方法詳解(Marshal,UnMarshal)
這篇文章主要介紹了Go處理json數據的方法詳解,Marshal(),UnMarshal(),需要的朋友可以參考下2022-04-04
Go語言生成UUID的利器(github.com/google/uuid)
UUID是確保每個元素唯一性的重要工具,Go語言雖然在標準庫中沒有直接提供UUID生成功能,但可以通過安裝github.com/google/uuid庫來實現,本文就來介紹一下,感興趣的可以了解一下2024-11-11
Go語言中io.Reader和io.Writer的詳解與實現
在Go語言的實際編程中,幾乎所有的數據結構都圍繞接口展開,接口是Go語言中所有數據結構的核心。在使用Go語言的過程中,無論你是實現web應用程序,還是控制臺輸入輸出,又或者是網絡操作,不可避免的會遇到IO操作,使用到io.Reader和io.Writer接口。下面來詳細看看。2016-09-09

