当前位置: 首页 > 后端技术 > Java

Go1.18新特性:TryLock

时间:2023-04-01 15:37:29 Java

3遍草堂被折腾N次大家好,我是建宇。还记得之前写过一篇文章《Go 为什么不支持可重入锁?》,主要是介绍有其他语言经验的朋友,想让Go支持可重入锁,被狠狠拒绝了。老大总会有憋不住的时候,虽然不是可重入锁。但是在Go1.18中,实现了一个新的尝试获取锁的方法(TryLock),也有点那个味道。今天建宇就带大家来了解一下被折腾了3次的“他”。后台更新的新功能必然涉及到用户场景。时间来到2018年,@deanveloper提到了一个经典的加载场景:需要加载几个非常大的文件,我想要一个进度条来显示我离完成还有多远。他认为这个进度条可以用TryLock来实现。以下是他的示例代码:func(b*ProgressBar)Add(nint){atomic.AddInt64(&b.Progress,int64(n))ifb.Progress>=b.Max{b.once.Do(b.updateClientsDone)return}ifb.pctMx.TryLock(){deferb.pctMx.Unlock()b.updateClients()}}上面代码的基本逻辑就是不断更新计数器,然后实现他的滚动加载进度bar通过尝试获取锁。因为老板们觉得用channel+select-default来做会更好,这个用例不足以支持TryLock的功能增加,又被拒了。经过2013年和2018年的大量讨论,时间又来到了2021年。@TyeMcQueen举了一些h2库的例子,表达了对TryLock方法会更好的一些期待。但是也被否决了,RussCox反对的理由是:互斥体是用来保护不变量的。如果锁由其他人持有,则您对不变量无话可说。TryLock方法鼓励对锁的不精确思考;它鼓励对不变量的假设,这些假设可能是正确的,也可能不是正确的。这最终成为它自己的竞争来源。在之前的失败案例中,RussCox认为给出的案例不足以说服加入TryLock系列方法的理由。我觉得需要补充的人越来越多了,谷歌老大DmitryVyukov给出了如下案例:就是gvisor、v.io/x/lib/nsync、trivago/tgo等软件库等都是使用TryLock这类方法的实现,与模拟代码基本一致。最后RussCox放手了,说:“每个人都同意这是不幸的,但有时是必要的”,感觉勉强同意了。考虑是给一个官方的实现,而不是各种第三方的TryLock方法,效率很低,重复。历史的整体时间线是这样的:@lukescott在2013年提出《sync: mutex.TryLock》,被拒绝了。2018年@deanveloper提议《proposal: add sync.Mutex.TryLock》,被拒绝。2021@TyeMcQueen提议《sync: add Mutex.TryLock》,先被拒绝,然后被接受。2022年,由于Go1.17的特性已经冻结,计划在Go1.18(3月)发布。即将到来的Go1.18中的新方法sync.TryLock,主要是增加了sync标准库中TryLock系列的相关方法。如下图所示:Mutex.TryLock:尝试锁定互斥量,是??否成功返回。RWMutex.TryLock:尝试加锁读写锁,是否成功返回。RW互斥锁。试试RLock。尝试加读锁,返回是否成功。官方提醒:虽然使用TryLock的场景确实存在。但应该很少见,经常使用TryLock可能是更深层次问题的迹象。综上所述,在Go1.18中,尝试获取锁的TryLock方法终于落地。这种方法的存在有利也有弊。看来以后可能会成为if-else的常用判断,也可以避免很多锁导致的long-hold。但是,从应用程序设计的角度来看,使用这种方法是有问题的,需要特别注意和思考。9年后,不容易。如有任何问题,欢迎在评论区反馈交流。最好的关系是相互成就。您的好评是创作炸鱼最大的动力。感谢您的支持。文章持续更新中。可以微信搜索【脑补炸鱼】阅读。本文已收录在GitHubgithub.com/eddycjy/blog中。学习Go语言可以看Go学习地图和路线。欢迎星星提醒。