当前位置: 技术文章>> 100道Go语言面试题之-在Go中,如何实现协程(goroutine)之间的同步?
文章标题:100道Go语言面试题之-在Go中,如何实现协程(goroutine)之间的同步?
在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语言通过通道、互斥锁、读写互斥锁和条件变量等机制提供了丰富的协程间同步手段。开发者可以根据具体场景和需求选择最合适的同步机制。在多数情况下,通道因其简洁性和内置于语言的特性,是协程间通信和同步的首选方式。