当前位置: 首页 > 科技观察

Go1.18新特性:什么是TryLock?你需要它吗?

时间:2023-03-21 11:39:37 科技观察

大家好,我是polarisxu。我们知道Go标准库的sync/Mutex和RWMutex实现了sync/Locker接口,提供了Lock()和UnLock()方法,可以获取和释放锁,我们可以方便的使用它们来控制并发共享资源控制。(其他语言,比如Java,有类似TryLock的功能)typeLockerinterface{Lock()Unlock()}但是在获取到锁之后,其他goroutine如果在Lock释放之前调用Lock,就会被阻塞。这种设计在某些情况下可能不能满足需要。有时候我们想尝试获取锁,如果获取到了,就继续执行。如果拿不到,我们也不想阻塞,而是调用其他逻辑。这时候我们就想要TryLock方法:也就是尝试去获取锁,但是获取不到,也没有被阻塞。这个要求在2013年提出,但政府没有采纳。2018年有人提出:https://github.com/golang/go/issues/27544,建议加入TryLock,但是没有下文。直到2021年4月,有人再次提出来,还给出了标准库中需要的场景:https://github.com/golang/go/issues/45435。然而,GoTeam的负责人rsc提出了反对意见:锁是为了保护不变量。如果锁由其他人持有,那么关于不变量你就无话可说了。TryLock鼓励对锁的不精确思考;它鼓励对可能正确或不正确的不变量做出假设。这最终成为它自己的种族来源。http2中肯定存在锁定问题。添加TryLock可以让我们在某种程度上掩盖它们,但即使那样也不是真正的解决方法。这更像是你的四轮驱动越好,你被困得越远。我不认为http2为TryLock提供了令人信服的理由。他认为TryLock会鼓励设计师不精确地思考锁,这可能最终成为竞争(竞争)的根源。同时,他认为只为http2提供TryLock不值得,希望能有更有说服力的案例。然后大家讨论了一下,rsc给出了一个实现,并提到:sync:addMutex.TryLock,RWMutex.TryLock,RWMutex.TryRLock这些函数的使用几乎(但不是)总是一个坏主意。很少有必要,并且第三方实现(例如使用互斥锁和原子字)无法像包同步本身中的实现那样与竞争检测器集成。这是Go1.18目前实现的三个方法。但是,rsc建议您尽量不要使用它。可以看出最后rsc被攻破了,因为有人想出了一些实现TryLock的代码。正如neild所说,虽然TryLock大部分时候可能用不到,但是TryLock有各种第三方版本也不是什么好事,不过官方应该有一个实现吧。看看官方的Mutex.TryLock实现:https://pkg.go.dev/sync@master#Mutex.TryLock强调一下,虽然正确使用TryLock的情况很少见。看得出来官方是勉强加上的。关于TryLock,鸟巢君在2017年写了一篇关于如何自己实现一个的文章,比较了几种实现方式的性能。感兴趣的可以阅读:https://colobu.com/2017/03/09/implement-TryLock-in-Go/。本文转载自微信公众号「polarisxu」,可通过以下二维码关注。转载本文请联系polarisxu公众号。