關於 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

往期推薦

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