基础题。这个问题暗示了 Go 中 map 的遍历顺序是不确定的。你在回答的时候,要多回答几个可行的解决方案,最终还要总结升华一下不应该依赖于 map 中的键值对顺序。
基础题。基本上你可以认为如果一个数据结构没有说自己是并发安全的,那么就肯定不是并发安全的。在回答这个问题的时候,可以将话题引导过去 sync.Map 这个线程安全的结构上。
基础题。Go 的异常处理机制和别的语言并不一样,主要是 panic 和 error。
而要刷亮点,你就要结合自己的使用体会,讨论什么时候使用 panic,什么时候使用 error。
基础题,在校招和初级工程师面试中比较常见,尤其是如果你面的是 Go 之类的内置了协程的语言的岗位,会更加容易遇到。
要在这个问题之下刷出亮点,最好就是讲清楚沿着进程、线程和协程三者的演进趋势。
略难的理论题。不懂这个也不影响你使用 Mutex。要回答好这个问题,就要详细解释为什么 Mutex 会搞出来这两种模式。
基础题。要想回答好,既要回答出来两种 channel 用起来的差异,更重要的是可以稍微深入讨论一下 channel 的缓冲大小该如何确定,最后揭示 channel 无法动态调整缓冲区大小的弊端,以及对应的解决方案,完成绝杀。
理论和实践并重的题目。在实践中,如果你不注意 goroutine 阻塞,很可能写出 goroutine 泄露的代码,或者写出死锁的代码。因此在回答的时候你也可以讲一个你经历过的 goroutine 不小心阻塞的场景。
如果你已经背了 GMP 调度的内容,可以提及当 goroutine 阻塞之后,P 会调度别的 goroutie,从而将问题引导到别的地方。
理论和实践结合的题,稍微有点难度。在回答的时候,最好能够给出具体的排除内存泄露的案例,并且进一步讨论内存泄露和 goroutine 泄露的关系。
如果你使用过实验特性 Arena,那么就可以进一步谈 Arena 造成的内存泄露,这个是比较有特色的,能给面试官留下深刻印象。
稍微有点难的题。实践中其实除非是做中间件研发的,不然的话 Go 的 GC 没啥好调的。应该说,和 JAVA 花里胡哨的调优比起来,Go 的调优可以说是 so easy。你在回答这个问题的时候,最好就是加一些调优的案例。
你可以用减少 GC 的案例进一步刷亮点,毕竟 Go 都没啥好调优的,所以在别的调优上就更加重要了。
从理论上来说内存逃逸是一个比较高级的话题,正常面试一般的业务研发岗位是犯不着面的,毕竟随便优化一个 SQL 就比你千辛万苦优化内存逃逸来得收益大得多。但是呢,国内总有一些面试官喜欢装逼,所以你有时候会遇到这个问题。
要想回答好,最佳策略是在解释了基本概念之后,加一个自己使用的内存逃逸优化案例。
基础题。这道题要刷好亮点,就要记得提 context 出来的背景,并且综合对比别的语言中的 Thread Local 解决方案,以及很早期的开源的利用 unsafe 实现的 goroutine local 机制。
基础题。slice 是一个对 Go 初学者非常不好的概念,我建议转语言的同学将 slice 看成是一个功能非常有限的 ArrayList,这样所有的问题你都能理解了。所以你要刷亮点,也是要讨论到 ArrayList。
最后我提及了我的一点思考作为刷亮点的东西,你可以考虑是否采用。总之就是我个人认为 slice 并不是什么好东西,看上去更加像是早期没有泛型而引入的一种东西。
基础题。这个题目主要考察的是 channel 的阻塞特性,除了要回答一般的读写引发的阻塞以外,不要忘了关闭和未初始化 channel 这两种情况。
在实践中,很多时候 goroutine 泄露都是因为 channel 使用不当引起的,尤其是在复杂的并发场景下,更是难以分析 channel 谁在发数据,谁在收数据,因此你可以从这个角度讲讲自己的实践,刷一个亮点。
理论题。懂不懂这个底层原理都不影响你写 Go 代码。要刷出亮点来,你就需要根据 defer 的底层原理总结出使用 defer 的最佳实践,或者说高性能实践。
基础题,实践题。在这个问题之下,我有一个绝佳的点可以让你刷出亮点,也就是一些公司会用 panic 而不是 error 来传递错误,任何错误。当然,这种实践我是非常反对的。
基础题。要点是回答出来 case 是随机挑选,而后再进一步解释为什么要做成随机的。不过要想刷好亮点,就可以深入讨论 case 的时机问题。
基础题。和别的语言比起来,Go 的一个优势就是直接在语法层面上支持了协程。而且在实践中,你也会经常开启 goroutine 来异步执行一些代码。要想回答好这个问题,最基本的回答就是和线程比,但是要想刷出亮点,就得深入讨论 Go 引入协程之后在一些编程模型上和别的语言的区别。对于应届生来说,这个问题应该会更加容易被问到。
基础题,侧重于实践的问题。这个问题实际上考察的是你在实践中怎么协调协程,包括怎么传递数据,怎么达成同步,怎么发送信号。所以你可以尽可能罗列你知道的方式,引导面试官后续提问。但是最最基础的,channel 你还是需要回答出来的。并且,这个问题经常是用来开启 Go 并发编程这个面试主题的,所以你要有一个心理准备。
看上去难,实际上并不难的题,主打的就是一个死记硬背。在面试的时候要想刷出亮点,除了要把 Go 的内存对齐规则讲清楚,还要考虑进一步延伸到不同语言的内存对齐原则,并且给出利用这种对齐规则的具体案例。另外,要小心面试官手写一个结构体让你计算这个结构体在内存中的长度。
基础题,实践题。你在实践中至少要知道 defer 的执行顺序,不然运行结果可能就不如你的预期了。在回答的时候,要记得强调一个点,即便是 panic 也不会影响 defer。
稍微有点难的题,对于很多人来说很难理解它的行为,记住一句话就是,defer 对修改是可见的。
略难的题,纯理论题,你了不了解 GMP 调度都不影响你写出来牛逼的代码。这个题目之所以难,纯粹是因为要背诵的内容比较多,很多人会觉得全部背下来有点困难。
要回答好这个问题,能够将原理解释得很清晰,就可以赢得竞争优势了。如果你还能深入讨论 GMP 为什么设计成这个样子,就能在面试中赢得巨大的竞争优势了。
略难的题,可以看做是 GMP 调度下的一个子问题。
回答这个问题要求你深刻理解全局队列 + 局部队列 + 工作窃取这三点。同样刷亮点,也是通过举例子说明这种思路在实践中很常见。
略难的题。你如果机械背诵八股文,那么遇到这种问题就可能没有思路。
其实这种题目回答起来都是差不多的套路,具体到这里就是根据 GMP 调度原理总结优缺点,而后得出结论 GMP 就是行,GM 就是不行,GP 也是不行。
略难的题,不过依旧是基于 GMP 调度原理衍生出来的问题。
略难的题,同样是 GMP 调度衍生出来的问题。
在回答的时候,要想刷出亮点,就可以深入讨论局部性原理对程序设计的影响,并且举几个例子。当然了,这个问题的答案你也可以用在回答 GMP 调度相关问题中,刷一个亮点。
基础题。一般来说,面试官问这个问题,指向的是垃圾回收,也就是他真正想问的是垃圾回收的问题。不过他问法不够准确,因为内存管理包含两方面的内容:正向的内存分配和反向的垃圾回收。
因此你在回答的时候要既要提及内存分配,也要提及垃圾回收。并且因为这个问题问的内容非常宽泛,所以你可以在回答中尽可能提及非常多的技术点、词汇,从而引导面试官接下来的追问。
略难的题,也是基于 GMP 调度衍生的题目。这个问题的核心并不是真的讨论系统调用的流程,而是讨论如果系统调用阻塞了 M,GMP 调度会怎么办。
而这一句话就能说清楚,M 和 P 解绑,完成之后再绑定,重新调度。
可以简单,也可以难的题。如果你面试的岗位很高端,那么可能面试官是真心想和你探讨;但是如果你面试的岗位不是很高端,那么大概率他就是随口一问。在后一种情况下,你差不多随便回答一点就可以。
略难的题。如果你第一次遇到这个题目,你可能都不知道面试官是什么意思。
实际上,这个问题问的是如果一个 G 需要很长时间来运行,比如说一个无限循环,那么在它被调度到一个 P 之后,是不是它永远不会的让出这个 P,直到自己运行结束?
你大概率能够想到系统调用和等待锁两种情况会导致 G 让出 P,但是实际上还有别的东西,并且可以进一步扩展以引申到别的方面,刷出亮点,赢得竞争优势。
略难的题,因为要背的东西稍微有点多。为了防止面试官故意找茬,你在回答的时候要同时提及栈分配和堆分配,并且要详细解释堆分配的过程。
在这个问题下有一个极好的刷亮点方式,就是和 Linux 的 SLAB 进行对比,又或者和你了解的其它任何的内存分配原理进行对比。
如果你是应届生,那么你也可以进一步将这个内存分配过程和你学习的内存管理知识结合起来。
简单的,带陷阱的题。
如果要是面试官水平一般,他可能就是问你极小对象分配器。如果是高端面试官,他可能就是在这个题目里面设置了陷阱。但是不管怎样,你都要假设对面的面试官是一个高水平的面试官,防止翻车和 PUA。
我其实很难理解就是一些面试官在这种纯理论题下设置陷阱的心态,因为你又不是高考,搞这种陷阱就相当于“茴香豆的茴字你会几种写法”,没有任何意义。
略难的题。难点就是在于你要识别出来这个问题本质上就是问你 mcache 的优点,你就千万不要回答你不是设计者,你也不知道为什么用 mcache。
回答的时候,你要进一步和 P,以及 GMP 调度中的局部队列关联在一起,刷亮点的同时,还有可能将话题引导到 GMP 调度上。
简单题。唯一的难点就是你可能不知道什么是大对象,它一般是指 32KB 以上的对象。
略难的题。这个题目有两个点,第一个点是看你知不知道 Go 内存分配一堆极小对象做了什么特殊处理;第二个点是看你怎么理解这种特殊处理。
你在回答的时候,可以引用 Go 文档中的解释,从而证明你是一个看过源码的人,刷出亮点。
难的题,难就难在有很多细节。不过大部分情况下,面试官也不懂,尤其是那些搞业务开发的,没看过源码也说不出个所以然来。
因此你只要回答出来足够的细节了,尤其是怎么和 mspan,mcache,mcentral,mheap 结合起来,就足够刷出亮点了。
略难的题。对于刚接触垃圾回收的人来说,要背的东西还是有点多的。但是对于 JAVA 那边转语言过来的人来说,这点子内容还是很简单的。
回答这个问题的时候,只需要尽可能把知道的关键技术点说出来就好,但是不需要把所有的细节都说完,等着面试官追问。
如果你之前已经了解过别的垃圾回收算法、实现,那么就可以进行对比,刷出亮点。
比较简单的题。
要在这里刷亮点,非常关键的点就是指出寄存器里面的值,在不能确定类型的时候,只能假设这是一个指针,也要执行扫描。
略难的题。这个题目,你把最基础的三色标记法答出来也算过关,你进一步回答强弱三色不变性就能进一步刷亮点,当你把读写屏障就回答出来了,就差不多算是刷出来很多亮点了。
这里要记得进一步揭露读写屏障的本质,才算是功德圆满,无可挑剔。
基础题。这个题目比较经常在跨语言的场景下问出来,例如说你们公司从某个语言转到了 Go。回答这个问题其实也很简单,就是列举 Go 的优点,如果发问的场景和跨语言有关,也就是面试官其实隐藏了希望你比较不同语言之间的优缺点,那么你就增加优缺点比较的部分。
这个问题本身也是一个宽泛的问题,所以你可以在回答的时候尝试加入一些关键引导词。
基础题上加了一点点难度的题,在 Go 语言面试中非常常见,是一个很好的刷亮点的机会。从实践中来说,你知不知道这个东西,都可以写出很好的代码。
回答这个问题,要在回答了底层原理的基础上,重点讨论扩容的过程,以及最为关键的扩容因子的选择。
基础题,不太常见的问题。
之前流行的一种说法,是 Go 中的切片是引用传递。当然我个人是不认同这种说法的,在 Go 里面只有值传递一种。因此切片必然是值传递的,只不过传递的是切片本身。
简单高频题。在大部分 Go 的基础面试里面,这都是必问题目,而且在校招里面,面的会更加多。
这道题是一个极好的刷亮点的机会。一个是要解释清楚 Go 的扩容机制,尤其是扩容因子,以及平滑变化的过程;第二则是要提及在扩容机制之后扩展到其他类似机制上,并且进一步深入讨论扩容的时机、权衡。
大部分情况下,你的竞争对手最多就是回答清楚扩容的流程,而没有办法在这个基础上深入讨论,因此你可以借助这个问题给面试官留下非常深的印象。
简单题,本质上就是问你两者之间的区别,但是他这个问法,你就要举出一些具体的实践场景。
这应该算是 Go 的专属问题了,毕竟在别的语言里面没有那么奇葩的切片。
略难的题。其实从理论上来说都很简单,只是说你可能实践中根本没有做过,所以理解起来会有点难。
正常来说,我都是建议你在简历上写自己擅长优化性能,包括在面试中也写自己擅长优化性能。因为擅长优化性能是一个极大的竞争优势,特别有助于你拿到 offer。而在这个问题之下就是展示你在 Go 语言层面上的优化性能的能力。
基本上,你能够回答出来两三点就可以赢得很多竞争优势了。
略难的题。逃逸分析是一个在中间件研发中很常见的性能优化手段,但是业务研发基本上接触不到。
你在回答的时候,最好是有具体的例子加以辅助证明。
简单题。
很多初学者在使用切片等内置类型的时候,不注意预估容量,这可能会导致代码运行的时候引起不必要的扩容。在面试的时候,你可以将这个做成你的性能优化案例,也就是通过修改代码,准确预估容量来减少扩容,或者减少内存浪费。
其实答案就是一定会触发 GC。这个题目你可以理解为针对 JAVA 背景的程序员的精准狙击,因为在 JAVA 里面也有一个类似的方法,但是 JAVA 却并不一定执行垃圾回收。