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

共 2481字,需浏览 5分钟

 ·

2022-06-21 01:18

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



推荐阅读


福利

我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。

浏览 70
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报