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>
This commit is contained in:
240
questions/13-Golang语言/并发编程进阶.md
Normal file
240
questions/13-Golang语言/并发编程进阶.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# 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)
|
||||
- 有实现无锁数据结构的经验
|
||||
|
||||
**并发编程**:
|
||||
- 理解如何避免数据竞争
|
||||
- 理解如何使用原子操作
|
||||
- 理解如何实现高性能并发程序
|
||||
Reference in New Issue
Block a user