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 |
关键点:
- WaitGroup:等待一组goroutine完成
- Mutex:保护共享资源
- RWMutex:读写分离,提高读性能
- Once:确保代码只执行一次
- Pool:复用对象,减少GC压力
准备好学习Context了吗?让我们进入下一章!
最后更新:2026-03-26