现在技术文章特别卷,啥啥底层都能给你分析的头头是道,但是分析的对不对要看作者水平,很有可能一个错,抄他的那些人也跟着错,因为我以前看源码的时候就经常感觉自己在两种状态下切换:懂了 / 娘咧漏看了,这个函数干啥的。
八股文这个事儿,其实也特别考验面试官,如果只会一味的问八股文,那也只能说你正巧比面试的人多看点八股,并不能彰显你多有水平,换个小年轻当面试官人家也能干啊。
最近跟以前的老同事聊,他说了个他特别爱问的面试题,我觉得还是挺有水平的,既能引导候选人循序渐进地展开思维,又能考察基础和动手能力。
PS:老哥是83年的,以前在一个广告平台公司 C++,Java,安卓啥的都干过,之前当过我领导,就是他让我刚来公司两星期就去会议室封闭参与用 Go 重构项目的,算是硬逼着我学了学 Go。
老哥说:Go 当初吸引人的地方不就是并发、Channel 这些嘛,其实用过后你会发现也就那样,宣传的有点过了,但是既然平时用 Go 开发,这块就一定得过关,那怎么并发和 Channel 都考察到呢?我一般会问:"Channel 和 并发掌握的熟练吧(一般没人会说不熟)那咱们先用 Channel 实现一个互斥锁",嘿,说你呢,实现一下。
我心想这题我面试别人用过,我背过……,还能难倒我:先初始化一个 capacity 等于 1 的 Channel,它的“空槽”代表锁,哪个协程能成功地把元素发送到这个 Channel,谁就获取了这把锁,给你上代码:
// 使用chan实现互斥锁
type Mutex struct {
ch chan struct{}
}
// 使用锁需要初始化
func NewMutex() *Mutex {
mu := &Mutex{make(chan struct{}, 1)}
mu.ch <- struct{}{}
return mu
}
// 请求锁,直到获取到
func (m *Mutex) Lock() {
<-m.ch
}
// 解锁
func (m *Mutex) Unlock() {
select {
case m.ch <- struct{}{}:
default:
panic("unlock of unlocked mutex")
}
}
老哥说:只要不是太混,这个道题都能答出来,那么接下来我一般会在这道题的基础上两个变种,首先让候选人再扩展一下给这个锁实现 TryLock 功能,TryLock 知道吧,你不是写过两年Java,这个用过吧,你在刚才的基础上实现一下。
我心想:我现在偶尔写Java 的时候都是把以前做的那些项目代码翻出来抄抄,我哪能记得这么清楚,不过这个不就是尝试获取锁,获取不到返回 false 嘛。
这里再给大家解释一下 TryLock 这个功能,下面这段话我从JavaDoc 里抄的:
tryLock() - 可轮询获取锁。如果成功,则返回 true;如果失败,则返回 false。也就是说,这个方法无论成败都会立即返回,获取不到锁(锁已被其他线程获取)时不会一直等待。
那这个也难不倒我啊,咱们学 Channel 的时候,都要学会利用 select+chan+default 的方式,避免程序阻塞住嘛,那我就套一下这个公式呗。(不过我老不写这个,语法我给忘了,多亏GoLand 提示我半天我才写出来,面试的时候一般在纸上写,咱们读者到时候记得贝贝哈)
// 尝试获取锁
func (m *Mutex) TryLock() bool {
select {
case <-m.ch:
return true
default:
}
return false
}
老哥:嗯,确实是这么个解法,不过你这写的也太慢了,算你过吧,其实我直接写估计也写不出来,天天开会手都生了。那好,这个变种如果能答出来,证明这个候选人基础应该还可以,Channel 使用这块应该都没啥问题,那这会儿我就会再扩展一下,让候选人再实现下 TryLock 的重载方法,就是可以设置超时时间那个重载函数,考察一下他定时器这块的知识过不过关,诶,我怎么把答案给说出来了,你懂我意思吧。
老哥的意思就是实现一下 TryWithTimeout,Java 里锁的 Try Lock 还有个重载方法:
tryLock(long, TimeUnit) - 可定时获取锁。和 tryLock() 类似,区别仅在于这个方法在获取不到锁时会等待一定的时间,在时间期限之内如果还获取不到锁,就返回 false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回 true。
因为 Go 里边没有重载方法这种机制咱们就只能写个 TryWithTimeout 方法啦,刚才说了用定时器能实现,不过这块我也忘了怎么用了…...只好默默打开的了浏览器搜索,最后实现答案版本如下:
// 加入一个超时的设置
func (m *Mutex) LockTimeout(timeout time.Duration) bool {
timer := time.NewTimer(timeout)
select {
case <-m.ch:
timer.Stop()
return true
case <-timer.C:
}
return false
}
最后老哥看了看:嗯,看着挺像那么回事的,今天家里领导有事,我得赶紧接二公主放学了,下回再聊吧。
平时我们实际应用时最好不要用 Channel 替代sync.Mutex,但是用 Channel 确实除了实现互斥锁的功能外,还能扩充出TryLocK和LockTimeout这些扩展功能。
利用 select+chan+defualt 的方式,很容易实现 TryLock、TryLockWithTimeout 的功能。具体来说就是,在 select 语句中,我们可以使用 default 实现 TryLock,再加一个 Timer 来实现 Timeout 的功能。
本文标题:这三个Go水平自测题,手写不出来还是先老实上班吧
标题网址:http://www.shufengxianlan.com/qtweb/news8/432808.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联