關於 Go1.18 新函數 TryLock 的故事

語言: CN / TW / HK

爭做團隊核心程序員,關注「 幽鬼

大家好,我是程序員幽鬼。

今天給大家帶來一篇關於 1.18 新函數 TryLock 故事的文章。

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

這篇文章基於 Go1.18。

Go 1.18 有一個新函數 TryLock (用於互斥鎖 sync.Mutexsync.RWMutex ),它允許開發人員嘗試以非阻塞模式獲取鎖,即如果鎖已經被其他人獲取,該函數將簡單地返回 false 而不是等待鎖釋放。

這個函數激起了我的好奇心,因為雖然它的名字很明確,但它的用例並不明顯。讓我們收集有關它的信息以更好地瞭解其用法。

工作流程

為了更好地理解互斥鎖的工作流程,建議你閲讀這篇文章“ Go: Mutex and Starvation [1] ”。

在以下情況下,互斥鎖不可用:

  • 該鎖當前由另一個 goroutine 持有。

  • 未持有鎖,但互斥鎖處於 飢餓模式 [2] ;即,鎖將交給下一個等待者。

在以上任意一種情況下,函數 TryLock 都會立即返回 false 。這是一個總結這兩個用例的圖表:

TryLock返回false

這是一個相當快的操作,因為它只依賴於一位操作。

如果鎖可用,goroutine 將嘗試以與函數 Lock 相同的方式獲取它並返回此操作的結果。如果它不可用,goroutine 不會自旋或堵塞;這是一個完全非阻塞模式。

TryLock 解決了什麼問題?

函數文檔 [3] 明確指出,使用此函數的情況很少見:

注意,雖然 TryLock 的正確使用確實存在,但它們很少見,並且 TryLock 的使用通常表明在特定的互斥鎖使用中存在更深層次的問題。

事實上,多年來(參見 * *2012 年的這個討論* [4] *2013 年的這個問題* [5] ,或2013 年的 *這個其他討論 [6] ),這個功能似乎不需要甚至解決任何真正的問題,之前提到的討論都沒有帶來任何真實用例。那麼這個函數能給社區帶來什麼?實際上, 許多包 [7] 都試圖實現一個 TryLock 功能,但它們都不能與競態檢測器正確集成。至少,在官方的支持下,從原生的 race 檢測器中獲利變得更容易。

Go 標準庫和其他語言

Go 源代碼內部沒有使用這個新函數的地方。但是,Go 曾經 在 Go1.6 的 runtime 中具有類似的功能 [8] 。這用於在分析期間獲取鎖以掃描堆棧。如果運行時無法獲取鎖,則簡單地跳過跟蹤。

其他編程語言——Java:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html#tryLock、 Objective-C [9]Zig [10] 和許多其他語言——實現了相同的功能。 舊版本的 JRE 實現了這個功能 [11] ,為我們提供了另一個真實的用例:鎖保護了一個負責清除隊列的功能。由於隊列可以被任何線程清除並且不需要多次清除,因此第一個獲得鎖的線程將執行任務,而其他線程可以恢復它們的工作。

如果您曾經使用過此功能或瞭解  Go 或其他語言的另一個用例,歡迎分享交流。

作者:Vincent Blanchon,原文鏈接:https://medium.com/a-journey-with-go/go-story-of-trylock-function-a69ef6dbb410

參考資料

[1]

Go: Mutex and Starvation: https://medium.com/a-journey-with-go/go-mutex-and-starvation-3f4f4e75ad50

[2]

飢餓模式: https://medium.com/a-journey-with-go/go-mutex-and-starvation-3f4f4e75ad50#16b7

[3]

函數文檔: https://pkg.go.dev/sync#Mutex.TryLock

[4]

2012 年的這個討論 : https://groups.google.com/g/golang-nuts/c/MTaJNZ49u60?pli=1

[5]

2013 年的這個問題 : https://github.com/golang/go/issues/6123

[6]

*這個其他討論: https://groups.google.com/g/golang-nuts/c/vfbEGJCHGXM

[7]

許多包: https://github.com/search?l=Go&q=TryLock&type=repositories

[8]

在 Go1.6 的 runtime 中具有類似的功能: https://github.com/golang/go/blob/go1.6/src/runtime/mstkbar.go#L353

[9]

Objective-C: https://developer.apple.com/documentation/foundation/nslock/1418105-trylock?language=objc

[10]

Zig: https://github.com/ziglang/zig/blob/master/lib/std/Thread/Mutex.zig#L37

[11]

舊版本的 JRE 實現了這個功能: https://stackoverflow.com/questions/41788074/use-case-for-lock-trylock

往期推薦

歡迎關注「 幽鬼 」,像她一樣做團隊的核心。