关于 Go1.18 新函数 TryLock 的故事

2022年6月14日 212点热度 0人点赞 0条评论

争做团队核心程序员,关注「幽鬼

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

今天给大家带来一篇关于 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


往期推荐

欢迎关注「幽鬼」,像她一样做团队的核心。

图片

72920关于 Go1.18 新函数 TryLock 的故事

这个人很懒,什么都没留下

文章评论