八股探索

前言

由于误打误撞收到一份面试邀请,可是我才学不到半个月的golang,真的能通过一个中厂golang后端开发岗的面试吗?首先我学的时间短,其次我没背八股,然后我还没刷力扣算法题,而且go的项目一个都没有,这些事实都指向了这场面试我将被拷打。

但是肖佬说面试就是看运气,要我赶紧准备八股。我想想,也许面试官会偏向于招培养型人才,潜力型人才,那也许能碰碰运气咯。而且也能涨涨经验。

goroutine如何防止脏写

脏写也就是当我两个协程都同时给n++时,n可能只加1

方法有很多种:

加Mutex互斥锁:这里就尽量把少的会发生冲突的操作加入锁内,比如网络请求啥的这种协程自己的事情就没必要加入了;

读多写少的情况加RWMutex读写锁:因为它允许读共享,但Mutex锁住了,就啥都只能单独进行;

转换操作为原子操作:也就是把n++写成更高级的,更繁琐的代码,那代码中的函数或者实例会强制把某种操作改为原子操作。

tips: channel阻塞如果发生在main协程中,就会发生死锁。

make和new有什么区别

new是分配内存的,make是初始化的。

拿 map举例,m := new(map[string]int),只是在内存中开辟了一个空间给m,且m被当作是零值,这里的m = nil,然而给map赋值时,是需要map有哈希表的,此时m仅仅只有个空值nil以及在内存中的地址,其它啥也没有,所以不能被赋值;

但是用m := make(map[string]int)时,m就被make初始化好了,不仅仅是被分配了内存,还初始化了哈希表啥的基层建筑,就能被赋值。

这里注意make一般用于slice、map、chan的初始化。

slice踩坑

首先,不能把slice理解为数组,而是数组是slice的底层数组,实际上的slcie是一个结构体:

1
2
3
4
5
type slice struct {
ptr unsafe.Pointer // 指向底层数组的指针
len int
cap int
}

ptr指针指向底层数组,所以假如s := []int{1,2,3},那么s = s.ptr = &s[0](切片中第一个元素的地址),然后slice和它底层的数组是内存中两个不同的东西,并不是底层数组是slice的一部分,而是slice的指针可以指向数组的地址。

扩容:当预留的内存空间不够用时,会重新申请一块更大的内存空间并把原数据拷贝过来,原来的内存空间会被GC回收。扩容大小一般是扩容为原来的2倍或者1.25倍

关于母子切片的内存关系

image-20260704112914510

也就是母子切片共享底层数组,修改其中一个也会影响另一个,但是当子切片append到超出了母切片预留的内存空间,那么它俩就会剥离,不再有关系。

函数传参方式对于切片的修改

如果给函数传参传的时slice而不是*slice,那么修改底层数组是可以全局生效,但是修改slice的三个属性就不行,因为go中的函数传参都是值传递,也就是传的是拷贝体,不存在引用传递,然后拷贝体和本体的ptr指针指向的是同一个数组,所以修改那个底层数组就会全局生效。

GMP调度模型

线程由操作系统调度,goroutine由go Runtime的GMP模型调度。

G为 goroutine,M可以理解为操作系统线程,P为逻辑处理器,它们关系为:

M + P → 执行 G

p的数量一般等于cpu逻辑核心数量。举例:

100000 个 G
8 个 P
十几个或更多 M

但此时运行的M只有8个

程序去内存找变量

要访问的内存是虚拟内存(每个程序会被分配一段逻辑连续的地址),然后虚拟内存会被映射到物理内存上

程序访问变量时,CPU使用变量的虚拟地址,MMU 先查询 TLB(也就是快表,一种Cache);如果未命中,再查页表得到物理页号,将物理页号与页内偏移组合成物理地址,最后访问物理内存(RAM)中对应的位置读取变量的值。

IO的select

Socket 是网络通信的端点,一个 TCP 连接建立在客户端 Socket 和服务端 Socket 之间。Linux 用文件描述符(fd)来标识 Socket。服务器会维护很多 Socket,每个 Socket 都有自己的 fd。select 可以同时监听多个 fd,当某个 fd 上有事件(如新连接到来或收到数据)时,通知程序去执行相应的 I/O 操作。I/O 本质上就是程序与外部设备(网络、磁盘等)之间的数据读写。

Icon
致谢名单
本作品由 Hafsun 于 2026-07-03 21:44:14 发布
作品地址:八股探索
除特别声明外,本站作品均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 欢迎回家
Logo
上一篇Eino初学下一篇学术研究总结