Files
interview/questions/13-Golang语言/go-concurrent-advanced.md
yasinshaw ab3a99f131 feat: add 10 Golang interview questions
Added comprehensive Golang interview preparation materials:
- 基础语法(值类型、切片、map、defer、接口、struct、new/make)
- Goroutine 和并发模型(与线程对比、调度模型、内存模型)
- 错误处理和测试(error、panic/recover、单元测试、Benchmark)
- 并发编程进阶(Mutex、RWMutex、WaitGroup、atomic、数据竞争)
- HTTP 和 Web 开发(Client、Server、中间件模式)
- 内存模型和垃圾回收(内存分配、逃逸分析、GC)
- 性能优化(pprof、内存优化、CPU优化、并发优化)
- 反射和 unsafe(反射性能、unsafe 使用场景)
- 接口和类型系统(类型断言、interface{}、类型嵌入、泛型)
- 数据库操作(database/sql、GORM、事务、SQL 注入防护)
- 项目结构和工程化(标准项目结构、Go Module、CI/CD)

Each file includes:
- Detailed questions and comprehensive answers
- Code examples and best practices
- Alibaba P7 level requirements

Total: 60 interview questions (50 backend + 10 Golang)

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-01 00:16:36 +08:00

241 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Golang 并发编程进阶
## 问题
1. sync.Mutex 和 sync.RWMutex 的区别?
2. sync.WaitGroup 和 sync.Once 的使用场景?
3. atomic 包的作用是什么?
4. 如何实现一个无锁队列?
5. 如何检测数据竞争Data Race
6. Go 的内存模型Happens-Before是什么
---
## 标准答案
### 1. Mutex vs RWMutex
#### **Mutex互斥锁**
```go
var mu sync.Mutex
func write() {
mu.Lock()
defer mu.Unlock()
// 写操作
}
```
---
#### **RWMutex读写锁**
```go
var mu sync.RWMutex
func read() {
mu.RLock()
defer mu.RUnlock()
// 读操作(多个 Goroutine 可以同时读)
}
func write() {
mu.Lock()
defer mu.Unlock()
// 写操作(独占访问)
}
```
---
**使用场景**
- **Mutex**:读写都少
- **RWMutex**:读多写少
---
### 2. WaitGroup 和 Once
#### **WaitGroup**
**用途**:等待一组 Goroutine 完成
```go
var wg sync.WaitGroup
func worker(id int) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i)
}
wg.Wait() // 等待所有 worker 完成
fmt.Println("All workers done")
}
```
---
#### **Once**
**用途**:确保函数只执行一次
```go
var once sync.Once
func initDB() {
once.Do(func() {
// 初始化数据库(只执行一次)
fmt.Println("DB initialized")
})
}
func main() {
initDB()
initDB() // 不会再次执行
}
```
---
### 3. atomic 包
#### **作用**
**原子操作**:无锁并发编程
---
#### **示例**
```go
import "sync/atomic"
var counter int64
// ❌ 非原子操作(数据竞争)
func increment() {
counter++ // 不是原子操作
}
// ✅ 原子操作
func incrementAtomic() {
atomic.AddInt64(&counter, 1)
}
// 读取
value := atomic.LoadInt64(&counter)
// 比较并交换CAS
old := atomic.LoadInt64(&counter)
atomic.CompareAndSwapInt64(&counter, old, new)
```
---
### 4. 检测数据竞争
#### **使用 go test -race**
```bash
# 检测数据竞争
go test -race ./...
# 运行程序
go run -race main.go
```
---
#### **示例**
```go
// ❌ 有数据竞争
func main() {
var counter int
go func() {
counter++ // 数据竞争
}()
counter++ // 数据竞争
}
// ✅ 无数据竞争
func main() {
var counter int64
go func() {
atomic.AddInt64(&counter, 1)
}()
atomic.AddInt64(&counter, 1)
}
```
---
### 5. Happens-Before
#### **定义**
**Happens-Before**:保证一个操作对另一个操作可见
---
#### **规则**
1. **Goroutine 创建**`go func()` happens-before `func()` 开始
2. **Channel**:发送 happens-before 接收
3. **Lock**Unlock happens-before 下一次 Lock
---
#### **示例**
```go
var a, b int
func main() {
go func() {
a = 1 // ①
ch <- struct{}{} // ②
}()
b = 2 // ③
<-ch // ④
// 保证了:
// ① happens-before ②
// ② happens-before ④
// 因此a = 1 一定会在 b = 2 之前执行
}
```
---
### 6. 阿里 P7 加分项
**深度理解**
- 理解 Go 的内存模型Happens-Before
- 理解 atomic 包的实现原理CAS
- 理解 RWMutex 的实现(写锁饥饿问题)
**实战经验**
- 有使用 -race 检测数据竞争的经验
- 有优化并发程序的经验(减少锁、使用 atomic
- 有实现无锁数据结构的经验
**并发编程**
- 理解如何避免数据竞争
- 理解如何使用原子操作
- 理解如何实现高性能并发程序