
同步就是控制各个Coroutine的运行先后。sync是 Go 标准库用于协程 (goroutine) 之间同步、并发安全控制。原则不要通过共享内存通信通过通信共享内存 (channel)。只有 channel 不方便时再用 sync 原语。在Go语言的sync包中提供了以下这些同步控制1. sync.Mutex —— 互斥锁这是一个排他锁同一时间只能一个 goroutine获取锁。用于解决读写竞争的问题。importsyncvarmu sync.Mutexvarcountintfuncadd(){mu.Lock()defermu.Unlock()count}上面的代码定义了一把mu互斥锁和一个全局变量count,在add方法中先获得锁然后进行count自增最后释放锁。这里的defer mu.Unlock()一定要放在Lock()之后这里又一次体责Go语言的简洁之处defer关键字可以保证在add函数调用结束时调用mu.Unlock()方法释放锁。为什么说defer很简洁呢比如说如果add函数很复杂有很多个地方会直接return那么如果稍有不慎就会忘记释放锁而defer让你没有这样的担忧它会在函数执行完时调用。不管函数在哪里返回或是发生了什么异常defer都会保证mu.Unlock()函数会被在最后被执行。简单点说就是defer会安排它后面的函数在在当前函数体结束时调用。2. sync.WaitGroup如字面意思一样这把锁用于等待一组 goroutine 完成。packagemainimportsyncvarw sync.WaitGroupfuncmain(){gofunc(){w.Add(1)deferw.Done()println(1)}()gofunc(){w.Add(1)deferw.Done()println(2)}()gofunc(){w.Add(1)deferw.Done()println(3)}()w.Wait()for{}}每个Goroutine开始就要调用w.Add() 增加计数结束时要调用w.Done()减少计数用w.Wait()等待这些Goroutine的完成。w.Wait()会阻塞到计数为0 。3. sync.RWMutex这是一把读写锁读共享、写独占。适合读多写少场景提升并发性能。varrw sync.RWMutexvardataint0funcRead()int{rw.RLock()deferrw.RUnlock()returndata}funcWrite(vint){rw.Lock()deferrw.Unlock()datav}RLock()/RUnlock()— 读锁Lock()/Unlock()— 写锁写锁优先级高一旦有写等待后续读会被拦住4. sync.Once仅执行一次。不管有多少 goroutine 调用函数只会执行 1 次常用于懒加载、单例初始化varonce sync.Oncefuncmain(){Init()Init()Init()}funcInit(){once.Do(func(){println(only once)})}5. sync.Cond条件变量。goroutine 等待某个条件达成手动唤醒。配合 Mutex/RWMutex 使用。packagemainimportsyncimportfmtvarmu sync.Mutexvarcondsync.NewCond(mu)varqueuemake([]int,0)funcmain(){Consume()Produce()for{}}funcProduce(){cond.L.Lock()queueappend(queue,123)cond.Signal()cond.L.Unlock()}funcConsume(){gofunc(){cond.L.Lock()forlen(queue)0{cond.Wait()}queuequeue[:]fmt.Println(queue)}()}Consume()函数中cond.L.Lock() 获得锁条件不满足调用cond.Wait()阻塞并且释放锁 在被唤醒后会重新拿到锁。Wait 必须放在 for‑loop 判断防止**虚假唤醒 **。Produce()获得锁cond.L.Lock()向队列添加元素条件满足调用cond.Signal()主动唤醒只能唤醒 1 个等待者如果要唤醒所有的等待者则需要调用cond.Broadcast()。6. sync.Map这是并发安全的map。Go 内置map不是并发安全多 goroutine 读写普通 map 直接 panic。sync.Map专门给高频并发场景设计的。适合读多写少、key‑value 基本不变如果频繁增删的场景则建议使用 Mutexmap。varm sync.Mapfuncmain(){m.Store(key1,Tom)m.Store(key2,GZ)m.Store(key3,value3)val,ok:m.Load(key2)fmt.Println(val,ok)m.Delete(key1)m.Range(func(key,valueinterface{})bool{fmt.Println(key,value)returntrue})}注意LoadOrStore()key不存在则存入。7. Channel我们另起一篇来讲。