云计算百科
云计算领域专业知识百科平台

最详细的后端面试系列内容—golang八股(持续更新中)

引言

这里是阳明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八股文的全部内容。有什么问题和意见以及其他想法的可以在评论区进行留言。如果这篇博客文章对你有帮助,可以点赞收藏加关注。你们的支持是我更新的最大动力。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 最详细的后端面试系列内容—golang八股(持续更新中)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!