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

3.6 KiB
Raw Blame History

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互斥锁

var mu sync.Mutex

func write() {
    mu.Lock()
    defer mu.Unlock()

    // 写操作
}

RWMutex读写锁

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 完成

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

用途:确保函数只执行一次

var once sync.Once

func initDB() {
    once.Do(func() {
        // 初始化数据库(只执行一次)
        fmt.Println("DB initialized")
    })
}

func main() {
    initDB()
    initDB()  // 不会再次执行
}

3. atomic 包

作用

原子操作:无锁并发编程


示例

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

# 检测数据竞争
go test -race ./...

# 运行程序
go run -race main.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. LockUnlock happens-before 下一次 Lock

示例

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
  • 有实现无锁数据结构的经验

并发编程

  • 理解如何避免数据竞争
  • 理解如何使用原子操作
  • 理解如何实现高性能并发程序