大厂面经 | 百度二面:Go 语言并发原语解析
大家好,我是老周。今天要和大家分享的是百度二面中 Go 语言并发原语相关面试题,接下来我会从Go 语言并发原语的定义、核心类型、应用场景等几个角度逐步拆解。
同时老周有制作相应视频讲解,想要详细了解此篇内容的同学可以关注小破站:*********。老周也会在上面持续分享相关稿件,内容包括300+大厂面试系列,GO保姆教程系列、开源项目推荐系列、面试八股文等(附相应资料PDF),都是免fei的注意骗子,如果有职业规划、面试中遇到的问题也可以找老周解答,这些帖子都是面试中同学的真实经历,感谢支持关注!
Go 语言并发原语解析:
并发原语定义
在 Go 语言中,用于支持并发编程的机制统称为并发原语,所有与 Go 语言并发编程相关的内容都可归为此类。
核心并发原语及应用场景
(一)Goroutine
Goroutine 是 Go 语言实现并发的核心,本质是轻量级线程,但并非所有场景都适合使用,不当使用可能导致性能下降,其主要应用场景包括:
- 并发任务处理:针对需独立处理的任务,如服务接收请求时,每接收一个请求就启动一个 Goroutine 处理,任务执行完 Goroutine 即结束,例如调用接口时,每调用一次启动一个 Goroutine 执行。
- 异步调用:当主流程不关心调用结果,无需等待结果返回即可继续执行后续逻辑时,可通过 Goroutine 模拟异步调用,只需保证任务执行完成。
- 后台任务:用于执行周期性操作,如微信公众号开发中获取接口调用凭据的定时任务,可通过 Goroutine 在后台定时运行。
- 并行计算:对于可拆分的大任务,将其拆分为多个无关联的小任务,启动多个 Goroutine 并行执行小任务,待所有小任务完成后,再进行大任务的后续流程,以提升整体计算速度。
(二)Channel
Channel 本质是 Goroutine 间线程安全的通讯方式,也可看作线程安全的容器,核心作用是实现 Goroutine 间通讯,具体应用场景如下:
- 数据传递与共享:在不同 Goroutine 间传递数据,实现数据的共享与交换,是 Channel 最根本的作用。
- 任务分发与结果收集:一方面可向多个 Goroutine 分发任务,如一个 Channel 中有 10 个消息,启动 10 个 Goroutine,遍历 Channel 获取消息并执行;另一方面,由于 Goroutine 无返回值,可让每个 Goroutine 执行完任务后向 Channel 发送结果,从而收集任务处理结果。
- 并发控制:通过设置有界缓冲区的 Channel 控制并发 Goroutine 数量,例如创建容量为 5 的 Channel,无其他 Goroutine 读取时可写入 5 个消息,读取一个消息启动一个 Goroutine,消息耗尽则不再启动,实现并发控制;同时,可通过 Channel 等待多个 Goroutine 完成任务,每个 Goroutine 完成后向 Channel 发送消息,Channel 满时则表示所有 Goroutine 任务完成。
- 事件通知:利用 Channel 关闭时的广播特性实现事件通知,所有监听该 Channel 的 Goroutine 都会收到广播消息,可用于通知多个 Goroutine 执行退出等操作,类似context包中Done方法通过 Channel 关闭触发 Goroutine 退出的机制。
- 配合 Select 实现 IO 多路复用:Select 可监听多个 Channel 的读、写事件,哪个 Channel 可操作就处理哪个,若多个可操作则随机选择一个,实现 IO 多路复用;且 Select 语句结合case和default,default可实现非阻塞机制,当无case可执行时,执行default下的逻辑。
(三)sync 包相关组件
sync包提供多种用于并发控制的组件,满足不同并发场景需求,各组件的作用与应用场景如下:
- WaitGroup
- 作用:等待一组 Goroutine 完成工作,通过计数器实现,启动 Goroutine 时计数器加 1,任务完成时减 1,计数器为 0 则表示所有 Goroutine 执行完毕。
- 应用场景:并行计算中,等待拆分后的所有小任务对应的 Goroutine 完成,再进行后续流程。
- Cond
- 作用:通知满足条件的 Goroutine 继续执行,不满足条件则阻塞。
- 应用场景:生产者 - 消费者模式,消费者需等待生产者生产消息(满足 “消息不为 0” 条件)后才执行,否则阻塞。
- 互斥锁(Mutex)与读写锁(RWMutex)
- 作用:保证线程安全和操作原子性。互斥锁为独占锁,加锁后仅当前 Goroutine 可操作;读写锁分读锁和写锁,读锁间可并发,写锁与读锁、写锁与写锁不可并发,性能优于互斥锁。
- 应用场景:互斥锁适用于读写频率相近或写操作频繁的场景;读写锁适用于读多写少场景,如 Go 的map(读操作线程安全)的并发访问。
- Once
- 作用:确保多 Goroutine 并发场景下,某函数仅执行一次,接收一个无参无返回值的函数。
- 应用场景:单例模式中的数据初始化,多个 Goroutine 可能同时触发初始化,用Once包裹初始化函数,保证仅执行一次。
- Atomic
- 作用:提供原子操作,确保共享变量的原子性和线程安全。
- 应用场景:需直接操作共享变量且保证原子性的场景,但 Go 更推崇用 Channel 实现数据共享(通过通讯共享内存),Atomic 是通过内存实现通讯,需额外处理并发问题。
- Map
- 作用:线程安全的集合,专门优化了高并发场景下的读写性能。
- 应用场景:高并发且存在读写操作的场景,若需使用map并保证线程安全,可替代 “map+ 锁” 的方案。
面试考察并发原语的原因
Go 语言原生支持并发编程,而并发原语是实现并发编程的核心手段。考察并发原语相关知识,可直观了解面试者对 Go 语言并发编程的理解深度和实际应用能力,且这些知识在工作中会频繁用于实战开发,相比 GC 原理等内容,更贴近实际业务场景。
配套学习资源
为了更加深入的理解,我为大家准备了 300 多道 Go 语言原生相关面试题及答案,涵盖多个领域,具体题目分布如下:
- Go 基础:31 道
- 代码分析:26 道
- 并发编程:9 道
- Redis:40 道
- MySQL(原文 “my circle” 疑为笔误):若干道
- Linux:18 道
- Go Timer:19 道
- 微服务:17 道
- 容器技术:74 道
- 缓存:10 道
- 网络和操作系统:27 道
- 消息队列:16 道
- 分布式编程:13 道
- Cassandra(原文 “catch” 疑为笔误):9 道
- MongoDB:9 道
- Basic Search(基础搜索):若干道
以上就是本次分享的内容,同时老周有制作相应视频讲解,想要详细了解此篇内容以及对应资料的同学可以关注小破站:*********。老周也会在上面持续分享相关稿件,内容包括300+大厂面试系列,GO保姆教程系列、开源项目推荐系列、面试八股文等(附相应资料PDF),都是免fei的注意骗子,如果有职业规划、面试中遇到的问题也可以找老周解答,这些帖子都是面试中同学的真实经历,感谢支持关注!
#大厂##数据人的面试交流地##计算机##程序员#