Alomerry Wu @ alomerry.com

golang 八股

Feb 28, 2024 · 11min · 3.4k · · updated at 8 months ago

map

map 在传参时的类型

map 传参时是值传递,传递的是 hmap 指针,在函数中操作 map 时,都是对 hmap 同一个 buckets 的操作,也因此调用函数修改 map 键值对时,会使 caller 中传递的 map 元素发生改变

Golang 如何做内存管理的,比如有一个 map,删除了其中某些 key,那么这部分内存如何释放

对于 map,删除元素不会释放内存,只会将元素位置置空,需要使用:定期备份、value 使用指针类型(删除后通过 gc 回收)

Go 使用 Map 需要注意的点

有序性、扩容机制、多并发安全问题

讲讲哈希表处理冲突的方法,map 底层数据结构

  • 处理冲突的方式正常有两种:一种是开放寻址法,即产生冲突后将依次向后存储,访问时需要依次检查;另一种是拉链法,即产生冲突时在对应位置链上新元素,访问时在该位置遍历链表
  • 在 go 中将以上两种方式结合,宏观上更贴近拉链法。结合 map 底层结构 hmap 中单个桶结构 bmap 为例,当定位到某个桶时,会依次填充桶中的八个位置,当填充满了之后会链上新的溢出桶继续存储。

你对 map 的理解?它是并发安全的吗?如果用原生 map 实现并发安全的话要怎么做

  • map 表达的事一种一对一的关系,是使用任意 key 通过哈希函数可以获得对应的 value
  • 不是并发安全的
  • 使用 sync.Mutex

map 并发安全吗?为什么

不支持并发读写,会在 mapassign 和 mapdelete 中标记 flag 正在写入,在写入结束前和 mapaccsee 中都会验证 flag 写入位是否修改,修改则会 fatal error 终止整个程序

是所有的 map 都不支持读写并发嘛?map 为什么要设计成不支持并发的

  • sync.map 支持并发读写
  • map 的典型使用场景是不需要从多个 goroutine 中进行安全访问,若是只是为少数程序增加安全性,导致 map 所有的操作都要处理 mutex,将会降低大多数程序的性能。
  • 并发导致 fatal error 基于 let it crash 思想

并发读写崩溃原理

map 的底层结构 hmap 里有 flag 字段,第三位位写入位 hashWriting,标记当前 map 是否在写入,并发修改、修改时读取会产生 fatal("concurrent map writes") 错误

nil map 和空 map 区别

  • nil map 是不能赋值的,因为没有初始化 TODO_更详细
  • nil map 可以取值,但都是空的

哪些能作为 map 的 key 哪些不能?

map 的 key 需要是可哈希的,func、map、slice 不支持

使用 map 时候哪些情况会出现 panic

读的过程中会有更新、删除操作时 多个写操作时

如果我们把一个 map 的 key 删除了,他的内存会释放吗?

不会释放 TODO_更详细

map 的扩容机制

  • go 中有两种扩容机制:一种是等量扩容,一种是翻倍扩容,解决了两种问题,当大量 key 计算出的哈希值都集中落到了某个桶时,或是桶链上了很多溢出桶,后续删除元素后,并不会合并溢出桶,会导致该桶链上了大量溢出桶,查找效率降低,退化成链表,此时需要等量扩容;当桶中的元素过多,元素数量和桶数量的比值超过 6.5 时,访问效率也会下降,此时需要翻倍扩容
  • 等量扩容会将对应桶的元素复制到新桶对应位置;翻倍扩容会根据 key 的哈希值将元素分流到新桶切片的两个对应位置

map 为什么遍历取出来的值顺序不一样

hmap 在初始化的时候会初始化一个随机数种子,遍历是会用通过种子去随机遍历 TODO_更详细

array/slice

字符串转成 byte 数组,会发生内存拷贝吗?

字符串底层结构是 StringHeader[^StringHeader],切片底层是 SliceHeader[^SliceHeader],使用 unsafe 包转换底层结构可以不发生内存拷贝

如何删除切片中的某一个元素

截取、拷贝、移位

切片的扩容机制

数组和切片的区别

数组需要声明长度,切片是动态数组,其长度并不固定,我们可以向切片中追加元素,它会在容量不足时自动扩容

你对 Slice 类型的理解

slice 数据结构,nil 切片和空切片

锁

go 语言实现一个非阻塞锁

atomic?channel?

atomic 包哪里用到了

sync.mutex、sync.map

mutex 是悲观锁还是乐观锁?

悲观锁和乐观锁结合

sync.Mutex 怎么使用

使用 Lock 加锁,UnLock 解锁

细说 go 的各种锁

互斥锁:有两种工作模式,正常模式和饥饿模式,正常模式获取锁失败时阻塞协程,并将协程按照 FIFO 顺序放入等待队列;饥饿模式锁会在释放时直接传递给等待时间最长的协程,并且多次获取锁失败的协程会放在等待队列的头部

goroutine

协程操作系统是没有感知的,它怎么知道协程被切换了

协程是在用户态进行切换的,操作系统无法感知

golang 中使用 goroutine 使用系统调用会阻塞线程吗

https://qiankunli.github.io/2020/11/21/goroutine_system_call.html

goroutine 可能泄漏吗?gorotinue 通信方式

  • 可能泄露(无法正常退出):协程永久阻塞无法唤醒(channel 收发阻塞)、死锁、无限循环
  • channel、ctx、全局共享变量

为什么 golang 的协程快

  • 协程栈内存小,切换上下文更快
  • 协程切换处于用户空间

协程适用什么场景

I/O 密集型、高并发

go 的 goroutine 共享栈吗

不共享栈(分配 goroutine 或者协程栈增长时会统一切换到 g0 栈 TODO_证明)

抢占式调度是如何抢占的

  • 插入栈增长代码
  • gc、系统监控中检查协程运行时间过长,修改 g 的标志位
  • 被抢占协程执行函数调用,检测到抢占标记,执行调度

了解调度器吗?你的理解?

限制 P 的个数的有哪些方案

  • 设置 GOMAXPROCS
  • 在容器中可以限制 CPU

两个协程同时访问一个全局变量,使用什么方法使他们不会阻塞

自旋、原子包操作、某些情况下读写锁

如何控制并发数

  • 利用缓冲 channel
  • 利用锁控制
  • 协程池 ants

内存

defer (4/6)

什么情况下会引发 panic

主动调用、数组下标越界、空指针、类型断言失败、过早关闭 HTTP 响应体、除以 0、关闭未初始化的 channel、重复关闭 channel、未初始化 map 直接赋值、sync 计数为负数

如何保存程序崩溃时的数据

recover

讲一下 defer

子 goroutine 的 panic 会不会被父 g 捕获

不会

如何捕获子 goroutine 的 panic

context

  • 超时处理
  • 优雅关闭怎么实现

channel

  • channel 长度为 0 的情况,具体讲讲
  • channel 内部结构是什么 有无缓冲并发数据读写问题 底层锁
  • channel 分配在堆上还是栈上的呢?
  • channel 和 go(估计是想说 goroutine)联合使用有什么奇迹?
  • 定义长度为 0 的 channel 可以吗
    • 可以,阻塞式 channel
  • 读写一个关闭的 channel 会发生什么,对未初始化的 channel 读写会怎么样
  • channel 有什么用?
  • golang 通过通信来实现共享内存
  • channel 主要使用在什么场景?

GC

  • golang 的垃圾回收,三色标记法
  • 局部变量垃圾回收?GC?谈谈 GC 说了三个算法 三色回收
  • 为什么 gc 会让程序变慢

调度

interface

  • 接口的原理了解吗?
    • 空接口底层是一个 eface 结构,非空接口底层是 iface 结构
    • 给空接口赋值时会记录动态类型元数据和动态值
    • 给非空接口赋值时会从变量中拷贝定义的方法,记录动态类型元数据和动态值
  • 如何复用 interface,如果用的 interface 实现 OOP 中的多态的话要怎么做?
  • golang 接口,隐式实现 golang 面向对象,组合方式
  • 两个 interface {} 能不能比较

error

  • 了解 Go 的错误类型吗

receiver

  • 为什么字段和方法分开写?优势是什么?知道函数接收器吗

反射/unsafe

其他

进程、线程和协程区别

  • 进程和线程的切换需要在内核态进行,受操作系统调度,协程由 scheld 在用户态调度
  • 进程线程的上下文内存大,协程需要的上下文很小
  • 进程的创建需要系统调用分配进程 ID、文件描述附表、进程地址空间、命名空间等;线程享有进程的文件描述符表、虚拟地址空间等,但是也拥有自己的内核数据结构,内核空间和用户空间
  • https://blog.csdn.net/qq_34147021/article/details/85654879?spm=1001.2014.3001.5506

框架 (0/12)

  • gin 里面的路由
  • grpc 底层原理
  • go 项目用了 gin 的那些模块
  • gin 的参数校验,如何校验字段(这个也没太听懂,我感觉是让讲json的tag,binding之类的)
  • 有了解过 Golang 有哪些现成的框架
  • 为什么要做这个项目,基于什么场景
  • 你觉得在你的方案中,最容易出问题的点在哪
  • 一般框架都需要用到消息中间件来做一个中转,消息传递怎么做的
  • rpc 调用中,客户端都发生了什么,要完成哪些工作
  • rpc 客户端如何处理请求失败(如何充实)
  • grpc 怎么用的
  • 为什么 grpc 速度快

题目 (0/4)

  • 火车站卖票,四个窗口,10000 张票,使用 golang 实现
  • 开五个协程,全部执行一个函数,怎么保证协程执行完全部打印
  • 使用协程交替打印字符
  • 利用 golang 特性,设计一个 QPS 为 500 的服务器

Reference

 
 comment..
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.0.1
Theme by antfu
2018 - Present © Alomerry Wu