sync包 #

一、sync包概述 #

sync包提供了基本的同步原语,用于并发控制。

二、WaitGroup #

2.1 基本用法 #

go
var wg sync.WaitGroup

wg.Add(1)    // 增加计数
go func() {
    defer wg.Done()  // 减少计数
    // 工作
}()
wg.Wait()    // 等待计数归零

2.2 等待多个goroutine #

go
func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d\n", id)
}

func main() {
    var wg sync.WaitGroup
    
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }
    
    wg.Wait()
    fmt.Println("All done")
}

2.3 注意事项 #

go
// 正确:在goroutine外部Add
wg.Add(1)
go func() {
    defer wg.Done()
}()

// 错误:在goroutine内部Add
go func() {
    wg.Add(1)  // 可能在Wait之后
    defer wg.Done()
}()

三、Mutex #

3.1 基本用法 #

go
var mu sync.Mutex
var counter int

func increment() {
    mu.Lock()
    defer mu.Unlock()
    counter++
}

3.2 保护共享资源 #

go
type SafeCounter struct {
    mu    sync.Mutex
    count int
}

func (c *SafeCounter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

func (c *SafeCounter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}

3.3 避免死锁 #

go
// 错误:重复锁定
mu.Lock()
mu.Lock()  // 死锁

// 正确:使用defer
mu.Lock()
defer mu.Unlock()

四、RWMutex #

4.1 读写锁 #

go
var mu sync.RWMutex
var data map[string]string

func Read(key string) string {
    mu.RLock()         // 读锁
    defer mu.RUnlock()
    return data[key]
}

func Write(key, value string) {
    mu.Lock()          // 写锁
    defer mu.Unlock()
    data[key] = value
}

4.2 特点 #

  • 读锁共享:多个读操作可以并发
  • 写锁互斥:写操作独占
  • 读写互斥:读写不能同时进行

4.3 性能优势 #

go
type Cache struct {
    mu    sync.RWMutex
    items map[string]string
}

func (c *Cache) Get(key string) string {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.items[key]
}

func (c *Cache) Set(key, value string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.items[key] = value
}

五、Once #

5.1 单次执行 #

go
var once sync.Once

func initialize() {
    once.Do(func() {
        fmt.Println("只执行一次")
    })
}

func main() {
    for i := 0; i < 5; i++ {
        go initialize()
    }
    time.Sleep(time.Second)
}

5.2 单例模式 #

go
type Singleton struct{}

var instance *Singleton
var once sync.Once

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

六、Pool #

6.1 对象池 #

go
var pool = sync.Pool{
    New: func() interface{} {
        return new(bytes.Buffer)
    },
}

func processData(data []byte) {
    buf := pool.Get().(*bytes.Buffer)
    defer pool.Put(buf)
    
    buf.Reset()
    buf.Write(data)
    // 处理...
}

6.2 复用对象 #

go
type Buffer struct {
    data []byte
}

var bufferPool = sync.Pool{
    New: func() interface{} {
        return &Buffer{data: make([]byte, 1024)}
    },
}

func getBuffer() *Buffer {
    return bufferPool.Get().(*Buffer)
}

func putBuffer(b *Buffer) {
    b.data = b.data[:0]
    bufferPool.Put(b)
}

七、Cond #

7.1 条件变量 #

go
var mu sync.Mutex
var cond = sync.NewCond(&mu)
var ready bool

func wait() {
    mu.Lock()
    for !ready {
        cond.Wait()
    }
    mu.Unlock()
    fmt.Println("Ready!")
}

func signal() {
    mu.Lock()
    ready = true
    cond.Broadcast()
    mu.Unlock()
}

7.2 生产者消费者 #

go
type Queue struct {
    items []int
    mu    sync.Mutex
    cond  *sync.Cond
}

func NewQueue() *Queue {
    q := &Queue{}
    q.cond = sync.NewCond(&q.mu)
    return q
}

func (q *Queue) Put(item int) {
    q.mu.Lock()
    q.items = append(q.items, item)
    q.cond.Signal()
    q.mu.Unlock()
}

func (q *Queue) Get() int {
    q.mu.Lock()
    for len(q.items) == 0 {
        q.cond.Wait()
    }
    item := q.items[0]
    q.items = q.items[1:]
    q.mu.Unlock()
    return item
}

八、Map #

8.1 并发安全Map #

go
var m sync.Map

m.Store("key", "value")
v, ok := m.Load("key")
m.Delete("key")
m.Range(func(key, value interface{}) bool {
    fmt.Println(key, value)
    return true
})

8.2 适用场景 #

  • 读多写少
  • key相对稳定
  • 需要并发安全

九、实际应用 #

9.1 并发计数器 #

go
type Counter struct {
    mu    sync.Mutex
    value int
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}

func (c *Counter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.value
}

9.2 并发缓存 #

go
type Cache struct {
    mu    sync.RWMutex
    items map[string]interface{}
}

func (c *Cache) Get(key string) (interface{}, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    v, ok := c.items[key]
    return v, ok
}

func (c *Cache) Set(key string, value interface{}) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.items[key] = value
}

9.3 并发队列 #

go
type Queue struct {
    mu    sync.Mutex
    items []interface{}
}

func (q *Queue) Push(item interface{}) {
    q.mu.Lock()
    defer q.mu.Unlock()
    q.items = append(q.items, item)
}

func (q *Queue) Pop() interface{} {
    q.mu.Lock()
    defer q.mu.Unlock()
    if len(q.items) == 0 {
        return nil
    }
    item := q.items[0]
    q.items = q.items[1:]
    return item
}

十、最佳实践 #

10.1 使用defer释放锁 #

go
mu.Lock()
defer mu.Unlock()

10.2 避免复制 #

go
// 错误:复制mutex
var mu sync.Mutex
mu2 := mu

// 正确:使用指针
var mu sync.Mutex
mu2 := &mu

10.3 选择合适的锁 #

  • 读写都频繁:Mutex
  • 读多写少:RWMutex
  • 简单计数:atomic

十一、总结 #

sync包要点:

类型 用途
WaitGroup 等待goroutine完成
Mutex 互斥锁
RWMutex 读写锁
Once 单次执行
Pool 对象池
Cond 条件变量
Map 并发安全Map

关键点:

  1. WaitGroup:等待一组goroutine完成
  2. Mutex:保护共享资源
  3. RWMutex:读写分离,提高读性能
  4. Once:确保代码只执行一次
  5. Pool:复用对象,减少GC压力

准备好学习Context了吗?让我们进入下一章!

最后更新:2026-03-26