Files
interview/questions/13-Golang语言/并发编程进阶.md
yasinshaw 7f3ab362b3 feat: rename Golang files to Chinese and supplement root files
Changes:
- Renamed all 10 Golang files from English to Chinese names
- Created 00-项目概述/项目概述.md with comprehensive project overview
- Created 08-算法与数据结构/算法与数据结构学习指南.md with detailed learning guide
- Created 12-面试技巧/面试准备进度.md with progress tracking
- Added .obsidian configuration for better markdown editing
- Updated Claude.MD with Chinese filename rule

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

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

241 lines
3.6 KiB
Markdown
Raw Permalink 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
- 有实现无锁数据结构的经验
**并发编程**
- 理解如何避免数据竞争
- 理解如何使用原子操作
- 理解如何实现高性能并发程序