最近有朋友私聊问我说“阳哥,最近的行情是不是变好了?”
我没有正面回复他,因为其实这个问题根本没有答案。(很抱歉我的标题骗到了你ovo)
我一直觉得讨论行情的“暖”和“寒”是没有意义的,举个很简单的例子:
当各个公司高喊“用工荒”,大量发放岗位的时候,照样有人找不到工作;当“降本增效”成为企业生存法则,各大企业都大量裁员的时候,照样有人能找到工作。
说到这里大家也应该懂我的意思了吧。
最近确实经常传来喜报,这里也给大家分享一下看看:
从简历已读不回,到加入组织后一个月内到手offer
35岁+程序员,一周到手俩offer
Java零基础学员实习上岸
为了找到工作,他们都是下了很大功夫的,不能因为一句“行情变暖”就忽视他们自己的努力,所有的东西都是靠自己争取到的。
换句话讲,行情变好还是变差,和我们没有一分钱关系,只管冲就完事了。
想都是问题,做才有答案!
Go常见面试题分享
01 ❤channel 死锁的场景
- 当一个channel中没有数据,而直接读取时,会发生死锁:
q := make(chan int,2)
<-q
解决方案是采用select语句,再default放默认处理方式:
q := make(chan int,2)
select{
case val:=<-q:
default:
...
}
- 当channel数据满了,再尝试写数据会造成死锁:
q := make(chan int,2)
q<-1
q<-2
q<-3
解决方法,采用select
func main() {
q := make(chan int, 2)
q <- 1
q <- 2
select {
case q <- 3:
fmt.Println("ok")
default:
fmt.Println("wrong")
}
}
- 向一个关闭的channel写数据。
注意:一个已经关闭的channel,只能读数据,不能写数据。
参考资料:Golang关于channel死锁情况的汇总以及解决方案
02 ❤对已经关闭的chan进行读写会怎么样?
- 读已经关闭的chan能一直读到东西,但是读到的内容根据通道内关闭前是否有元素而不同。
- 如果chan关闭前,buffer内有元素还未读,会正确读到chan内的值,且返回的第二个bool值(是否读成功)为true。
- 如果chan关闭前,buffer内有元素已经被读完,chan内无值,接下来所有接收的值都会非阻塞直接成功,返回 channel 元素的零值,但是第二个bool值一直为false。
写已经关闭的chan会panic。
03 说说atomic底层怎么实现的.
atomic源码位于sync\atomic
。通过阅读源码可知,atomic采用CAS(CompareAndSwap)的方式实现的。所谓CAS就是使用了CPU中的原子性操作。在操作共享变量的时候,CAS不需要对其进行加锁,而是通过类似于乐观锁的方式进行检测,总是假设被操作的值未曾改变(即与旧值相等),并一旦确认这个假设的真实性就立即进行值替换。本质上是不断占用CPU资源来避免加锁的开销。
04 channel底层实现?是否线程安全。
channel底层实现在src/runtime/chan.go中
channel内部是一个循环链表。内部包含buf, sendx, recvx, lock ,recvq, sendq几个部分;
buf是有缓冲的channel所特有的结构,用来存储缓存数据。是个循环链表;
- sendx和recvx用于记录buf这个循环链表中的发送或者接收的index;
- lock是个互斥锁;
- recvq和sendq分别是接收(<-channel)或者发送(channel <- xxx)的goroutine抽象出来的结构体(sudog)的队列。是个双向链表。
channel是线程安全的。
参考资料:Kitou:Golang 深度剖析 -- channel的底层实现
05 map的底层实现。
源码位于src\runtime\map.go 中。
go的map和C++map不一样,底层实现是哈希表,包括两个部分:hmap和bucket。
里面最重要的是buckets(桶),buckets是一个指针,最终它指向的是一个结构体:
// A bucket for a Go map.
type bmap struct {
tophash [bucketCnt]uint8
}
每个bucket固定包含8个key和value(可以查看源码bucketCnt=8).实现上面是一个固定的大小连续内存块,分成四部分:每个条目的状态,8个key值,8个value值,指向下个bucket的指针。
创建哈希表使用的是makemap函数.map 的一个关键点在于,哈希函数的选择。在程序启动时,会检测 cpu 是否支持 aes,如果支持,则使用 aes hash,否则使用 memhash。这是在函数 alginit() 中完成,位于路径:src/runtime/alg.go 下。
map查找就是将key哈希后得到64位(64位机)用最后B个比特位计算在哪个桶。在 bucket 中,从前往后找到第一个空位。这样,在查找某个 key 时,先找到对应的桶,再去遍历 bucket 中的 key。
关于map的查找和扩容可以参考map的用法到map底层实现分析。
06 select的实现原理?
select源码位于src\runtime\select.go,最重要的scase 数据结构为:
type scase struct {
c *hchan // chan
elem unsafe.Pointer // data element
}
scase.c为当前case语句所操作的channel指针,这也说明了一个case语句只能操作一个channel。
scase.elem表示缓冲区地址:
- caseRecv : scase.elem表示读出channel的数据存放地址;
- caseSend : scase.elem表示将要写入channel的数据存放地址;
select的主要实现位于:select.go函数:其主要功能如下:
- 锁定scase语句中所有的channel
- 按照随机顺序检测scase中的channel是否ready
- 2.1 如果case可读,则读取channel中数据,解锁所有的channel,然后返回(case index, true)
- 2.2 如果case可写,则将数据写入channel,解锁所有的channel,然后返回(case index, false)
- 2.3 所有case都未ready,则解锁所有的channel,然后返回(default index, false)
- 所有case都未ready,且没有default语句
- 3.1 将当前协程加入到所有channel的等待队列
- 3.2 当将协程转入阻塞,等待被唤醒
- 唤醒后返回channel对应的case index
- 4.1 如果是读操作,解锁所有的channel,然后返回(case index, true)
4.2 如果是写操作,解锁所有的channel,然后返回(case index, false)
参考资料:Go select的使用和实现原理
07 go的interface怎么实现的?
go interface源码在runtime\iface.go
中。
go的接口由两种类型实现iface和eface。iface是包含方法的接口,而eface不包含方法。
iface
对应的数据结构是(位于
src\runtime\runtime2.go
):
type iface struct {
tab *itab
data unsafe.Pointer
}
可以简单理解为,tab表示接口的具体结构类型,而data是接口的值。
itab
:
type itab struct {
inter *interfacetype //此属性用于定位到具体interface
_type *_type //此属性用于定位到具体interface
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
属性interfacetype类似于_type,其作用就是interface的公共描述,类似的还有maptype、arraytype、chantype…其都是各个结构的公共描述,可以理解为一种外在的表现信息。interfaetype和type唯一确定了接口类型,而hash用于查询和类型判断。fun表示方法集。
- eface
与iface基本一致,但是用_type直接表示类型,这样的话就无法使用方法。
type eface struct {
_type *_type
data unsafe.Pointer
}
这里篇幅有限,深入讨论可以看:深入研究 Go interface 底层实现
08 go的reflect底层实现
go reflect源码位于src\reflect\下面,作为一个库独立存在。反射是基于接口实现的。
Go反射有三大法则:
- 反射从接口映射到反射对象;
- 反射从反射对象映射到接口值;
- 只有值可以修改(settable),才可以修改反射对象。
Go反射基于上述三点实现。我们先从最核心的两个源文件入手type.go和value.go.
type用于获取当前值的类型。value用于获取当前的值。
参考资料:The Laws of Reflection, 图解go反射实现原理
09 go GC的原理知道吗?
如果需要从源码角度解释GC,推荐阅读(非常详细,图文并茂)
欢迎关注 ❤
我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。
没准能让你能刷到自己意向公司的最新面试题呢。
感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:面试群。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。