当前位置: 技术文章>> 100道Go语言面试题之-在Go中,如何实现协程(goroutine)之间的同步?

文章标题:100道Go语言面试题之-在Go中,如何实现协程(goroutine)之间的同步?
  • 文章分类: 后端
  • 3378 阅读
在Go语言中,协程(goroutine)之间的同步主要通过几种机制来实现,包括通道(channels)、互斥锁(sync.Mutex)、读写互斥锁(sync.RWMutex)、以及条件变量(sync.Cond,虽然较少直接使用,但在某些特定场景下很有用)。下面将详细介绍这些机制: ### 1. 通道(Channels) 通道是Go语言中最常用的协程间通信和同步的机制。通过发送和接收操作,协程可以在通道上进行阻塞等待,从而实现同步。 ```go ch := make(chan int) go func() { // 模拟耗时操作 time.Sleep(1 * time.Second) ch <- 1 // 发送数据到通道,如果通道已满,则等待直到有空间 }() // 等待接收通道中的数据 val := <-ch // 如果通道为空,则等待直到有数据 fmt.Println(val) ``` ### 2. 互斥锁(sync.Mutex) 互斥锁用于保护共享资源,确保同一时间只有一个协程可以访问该资源。 ```go var ( mu sync.Mutex data int ) func updateData(n int) { mu.Lock() // 加锁 defer mu.Unlock() // 解锁,确保即使在发生panic时也能释放锁 data += n } // 可以在多个goroutine中调用updateData ``` ### 3. 读写互斥锁(sync.RWMutex) 读写互斥锁是互斥锁的一个变种,允许多个协程同时读取共享资源,但写入操作是互斥的。 ```go var ( rwMu sync.RWMutex data int ) func readData() int { rwMu.RLock() // 加读锁 defer rwMu.RUnlock() // 解锁 return data } func updateData(n int) { rwMu.Lock() // 加写锁 defer rwMu.Unlock() // 解锁 data += n } // 可以在多个goroutine中调用readData和updateData ``` ### 4. 条件变量(sync.Cond) 条件变量依赖于互斥锁,用于在协程之间协调条件等待和条件通知。条件变量比简单的通道提供了更灵活的等待/通知机制。 ```go var ( mu sync.Mutex cond *sync.Cond ready bool ) func init() { cond = sync.NewCond(&mu) } func waitForReady() { mu.Lock() defer mu.Unlock() for !ready { cond.Wait() // 等待条件满足 } // 条件满足,执行后续操作 } func setReady() { mu.Lock() defer mu.Unlock() ready = true cond.Signal() // 通知一个等待的协程 // 或者使用cond.Broadcast()通知所有等待的协程 } // 可以在多个goroutine中调用waitForReady和setReady ``` ### 总结 Go语言通过通道、互斥锁、读写互斥锁和条件变量等机制提供了丰富的协程间同步手段。开发者可以根据具体场景和需求选择最合适的同步机制。在多数情况下,通道因其简洁性和内置于语言的特性,是协程间通信和同步的首选方式。
推荐文章