前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >这三个 Go 水平自测题,手写不出来还是先老实上班吧

这三个 Go 水平自测题,手写不出来还是先老实上班吧

作者头像
KevinYan
发布2022-10-27 10:43:01
2170
发布2022-10-27 10:43:01
举报
文章被收录于专栏:网管叨bi叨网管叨bi叨

现在技术文章特别卷,啥啥底层都能给你分析的头头是道,但是分析的对不对要看作者水平,很有可能一个错,抄他的那些人也跟着错,因为我以前看源码的时候就经常感觉自己在两种状态下切换:懂了 / 娘咧漏看了,这个函数干啥的。

八股文这个事儿,其实也特别考验面试官,如果只会一味的问八股文,那也只能说你正巧比面试的人多看点八股,并不能彰显你多有水平,换个小年轻当面试官人家也能干啊。

最近跟以前的老同事聊,他说了个他特别爱问的面试题,我觉得还是挺有水平的,既能引导候选人循序渐进地展开思维,又能考察基础和动手能力。

PS:老哥是83年的,以前在一个广告平台公司 C++,Java,安卓啥的都干过,之前当过我领导,就是他让我刚来公司两星期就去会议室封闭参与用 Go 重构项目的,算是硬逼着我学了学 Go。

老哥说:Go 当初吸引人的地方不就是并发、Channel 这些嘛,其实用过后你会发现也就那样,宣传的有点过了,但是既然平时用 Go 开发,这块就一定得过关,那怎么并发和 Channel 都考察到呢?我一般会问:"Channel 和 并发掌握的熟练吧(一般没人会说不熟)那咱们先用 Channel 实现一个互斥锁",嘿,说你呢,实现一下。

我心想这题我面试别人用过,我背过……,还能难倒我:先初始化一个 capacity 等于 1 的 Channel,它的“空槽”代表锁,哪个协程能成功地把元素发送到这个 Channel,谁就获取了这把锁,给你上代码:

代码语言:javascript
复制
// 使用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 提示我半天我才写出来,面试的时候一般在纸上写,咱们读者到时候记得贝贝哈)

代码语言:javascript
复制
// 尝试获取锁
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 方法啦,刚才说了用定时器能实现,不过这块我也忘了怎么用了…...只好默默打开的了浏览器搜索,最后实现答案版本如下:

代码语言:javascript
复制
// 加入一个超时的设置
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 并发相关的知识。完整源码已经收录到我整理的Go 开发参考电子书中,给公众号「网管叨bi叨」私信【gocookbook】关键字即可领取,里面收录了很多实用的内容。

平时我们实际应用时最好不要用 Channel 替代sync.Mutex,但是用 Channel 确实除了实现互斥锁的功能外,还能扩充出TryLocKLockTimeout这些扩展功能。

利用 select+chan+defualt 的方式,很容易实现 TryLockTryLockWithTimeout 的功能。具体来说就是,在 select 语句中,我们可以使用 default 实现 TryLock,再加一个 Timer 来实现 Timeout 的功能。

关于 Channel 和 定时器的基础用法,我瞅了眼以前有写过,如果你才刚接触 Go,可以看下面两篇基础内容:

两篇老文章,内容可以,但是排版非常之垃圾,大家看前得做好心理准备,😁

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-07-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网管叨bi叨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档