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