引言
这里是阳明Coding,本期带来的是给面试golang后端开发岗的朋友们,最详细的golang面试八股。golang的八股主要是围绕协程,内存模型,Channel等内容展开。话不多说,开始今天的沉浸式八股之旅

目录
引言
golang的协程说一下
gmp内存模型
三色标记法垃圾回收
make和new的区别
golang的map结构
有缓冲Channel和无缓冲Channel区别
golang并发安全
接口与反射
golang的故事
在开始沉浸式八股之前,我们先来开始一段golang的故事
Golang 的故事:一门“被工程师逼出来”的语言
Go 语言的诞生,并不是因为“世界上还不够多的编程语言”,而是因为工程师真的被现有工具折磨够了。时间回到 2007 年,地点是 Google 总部。
那一年,Google 的代码库已经大到令人崩溃:
-
数百万行 C++
-
编译一次动辄几十分钟
-
多核 CPU 已经普及,但并发编程却又复杂又危险
-
构建系统像一台随时会爆炸的机器
有一天,Google 的三位工程师坐在办公室里,对着缓慢的编译器发牢骚:
-
Rob Pike(Unix 老兵,《Unix 编程环境》作者)
-
Ken Thompson(C 语言之父、Unix 之父)
-
Robert Griesemer(编译器专家)
他们心里有一个共同的疑问:
“为什么写程序,反而变得越来越慢、越来越复杂了?”
他们想要一门什么样的语言?
不是“最强大”,而是最顺手。
他们列了一张“反需求清单”:
❌ 不要复杂的模板 ❌ 不要难以理解的继承层级 ❌ 不要漫长的编译时间 ❌ 不要让并发成为噩梦
相反,他们想要的是:
✅ 像 C 一样简单 ✅ 像 Python 一样写得快 ✅ 原生支持并发 ✅ 编译快到“几乎感觉不到”
于是,他们决定,干脆自己造一门语言。
Go 的名字,其实很“任性”
最初,这门语言的名字就叫 “Go”。原因很简单:
-
短
-
好打
-
好记
有人说它太随意了,但这恰恰符合 Go 的气质: 不炫技,不复杂,只向前走。
(后来为了避免和动词混淆,官方文档里更多使用 “Go language” 或 “Golang” 这个叫法。)
golang的协程说一下
golang的协程Goroutine是一种轻量级的线程,由go运行时管理。初始栈仅2kb,与线程M:N映射,高效利用系统资源。
func main() {
go func() {
fmt.Println("Goroutine running")
}()
time.Sleep(time.Second)
}
gmp内存模型
golang的gmp内存模型主要由三部分组成:
G:Goroutine,协程对象
M:Machine,系统线程,负责执行G
P:Processor,逻辑处理器,负责管理G队列
优势:减少线程频繁的创建和销毁,利用多核并行的优势,避免上下文切换开销。
golang垃圾回收的过程
在 Go 中:
-
对象在 堆(heap) 上分配
-
不再被引用的对象 → 垃圾
-
GC 的任务:
-
找出“还活着的对象”
-
回收“不可达对象”
-
尽量减少 Stop-The-World(STW)时间
-
1. STW(很短)
2. 并发标记(Mark)
3. STW(很短)
4. 并发清扫(Sweep)
三色标记法垃圾回收
初始标记时会进行一次stw暂停
标记过程:
-
GC Root(全局变量、栈变量等) → 灰色
-
灰色对象:
-
扫描引用
-
引用对象标为灰色
-
自己变黑
-
-
重复直到 没有灰色对象
强三色:任何黑色对象不能直接引用白色对象
弱三色:黑色对象可以引用白色对象,但必须有灰色对象作为中间媒介
写屏障是什么
在指针写入时,保证被引用的对象不会是“白色”。
-
插入写屏障(Dijkstra)
-
删除写屏障(Yuasa)
make和new的区别
make一般用于初始化slice,map,Channel。返回的是引用类型本身。是一个可以直接使用的对象
new用于分配内存,返回指针,返回指向零值的指针,并不可以直接使用
// new:返回指针
p := new(int)
fmt.Println(*p) // 0
// make:返回可用对象
s := make([]int, 0, 4)
s = append(s, 1, 2, 3)
golang的map结构
有缓冲Channel和无缓冲Channel区别
无缓冲Channel具有同步阻塞,生产和消费必须同时进行。适用于一些任务顺序执行的情况
ch := make(chan int)
go func() {
ch <- 1 // 阻塞,直到有人接收
}()
fmt.Println(<-ch)
有缓冲Channel为异步,缓冲区未满或不为空时不会阻塞。天然队列结构,适合生产——消费模型
ch := make(chan int, 2)
ch <- 1
ch <- 2
// ch <- 3 // 阻塞(满了)
fmt.Println(<-ch)
golang并发安全
1. 语言级别:Channel通过通信共享数据,而不是通过共享数据通,避免了并发下的一个数据竞争的问题。
2. 同步原语:
Mutex(互斥锁)
var mu sync.Mutex
count := 0
mu.Lock()
count++
mu.Unlock()
RWMutex(多读并发,写互斥)
var rw sync.RWMutex
rw.RLock()
// read
rw.RUnlock()
WaitGroup(等待一组Goroutine完成),不做数据保护,只做生命周期同步
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("done")
}()
wg.Wait()
Cond(条件变量)适合复杂等待条件,比Channel更底层
Once(只执行一次)并发安全的单例或者初始化
var once sync.Once
func initConfig() {
fmt.Println("init once")
}
once.Do(initConfig)
3. 原子操作:atomic包。CPU原子指令,无锁,高性能
接口与反射
golang的接口可以通过隐式实现,不需要implement关键字,只需要方法集匹配,就自动实现接口
type Reader interface {
Read(p []byte) (int, error)
}
type File struct{}
func (f *File) Read(p []byte) (int, error) {
return 0, nil
}
var _ Reader = (*File)(nil)
golang的context的作用
golang的context用于并发和调用链中传递取消信号,超市/截止时间以及请求级元素。用来控制Goroutine的生命周期,避免资源泄漏
它可以在多层函数调用和多个 goroutine 之间传播 取消(cancel)、超时(timeout/deadline) 和 元数据(value),
四个核心方法 Deadline 定义时间边界,Done 负责取消通知,Err 表示取消原因,Value 用于在调用链中传递请求级元数据。
以上就是后端面试问题——golang八股文的全部内容。有什么问题和意见以及其他想法的可以在评论区进行留言。如果这篇博客文章对你有帮助,可以点赞收藏加关注。你们的支持是我更新的最大动力。
网硕互联帮助中心



评论前必须登录!
注册