关于 Go1.18 新函数 TryLock 的故事
今天给大家带来一篇关于 1.18 新函数 TryLock 故事的文章。
这篇文章基于 Go1.18。
Go 1.18 有一个新函数 TryLock
(用于互斥锁 sync.Mutex
和 sync.RWMutex
),它允许开发人员尝试以非阻塞模式获取锁,即如果锁已经被其他人获取,该函数将简单地返回 false
而不是等待锁释放。
这个函数激起了我的好奇心,因为虽然它的名字很明确,但它的用例并不明显。让我们收集有关它的信息以更好地了解其用法。
工作流程
为了更好地理解互斥锁的工作流程,建议你阅读这篇文章“Go: Mutex and Starvation[1] ”。
在以下情况下,互斥锁不可用:
该锁当前由另一个 goroutine 持有。 未持有锁,但互斥锁处于饥饿模式[2];即,锁将交给下一个等待者。
在以上任意一种情况下,函数 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
参考资料
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
推荐阅读