面试题答案
一键面试可能出现的数据竞争问题
- 读 - 写竞争:当一个协程正在复制切片(读取切片数据),同时另一个协程对该切片进行写入操作(比如追加新元素、修改元素值等),会导致读取到不一致的数据。例如,复制操作可能读取到部分修改前和部分修改后的数据。
- 写 - 写竞争:多个协程同时对切片进行写入操作,比如同时追加元素,会导致切片内部数据结构的不一致,可能出现元素丢失、重复或者切片扩容机制紊乱等问题。
解决方案
- 使用
sync.Mutex
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
var slice []int
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
mu.Lock()
// 复制切片
newSlice := make([]int, len(slice))
copy(newSlice, slice)
// 模拟写入操作
slice = append(slice, id)
mu.Unlock()
}(i)
}
wg.Wait()
fmt.Println(slice)
}
- 原理:通过`sync.Mutex`的`Lock`和`Unlock`方法,保证在同一时刻只有一个协程能够访问和修改切片,从而避免数据竞争。
2. 使用sync.RWMutex
(适用于读多写少场景)
package main
import (
"fmt"
"sync"
)
func main() {
var rwmu sync.RWMutex
var slice []int
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
if i%2 == 0 {
wg.Add(1)
go func(id int) {
defer wg.Done()
rwmu.Lock()
// 复制切片
newSlice := make([]int, len(slice))
copy(newSlice, slice)
// 模拟写入操作
slice = append(slice, id)
rwmu.Unlock()
}(i)
} else {
wg.Add(1)
go func() {
defer wg.Done()
rwmu.RLock()
// 复制切片
newSlice := make([]int, len(slice))
copy(newSlice, slice)
rwmu.RUnlock()
}()
}
}
wg.Wait()
fmt.Println(slice)
}
- 原理:`sync.RWMutex`允许多个协程同时进行读操作(使用`RLock`和`RUnlock`),但在写操作时(使用`Lock`和`Unlock`)会独占切片,防止其他读写操作,适用于读多写少的场景,提高并发性能。
3. 使用sync.Cond
(更复杂场景下协调读写)
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
var slice []int
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
if i%2 == 0 {
wg.Add(1)
go func(id int) {
defer wg.Done()
mu.Lock()
for len(slice) > 0 {
cond.Wait()
}
// 复制切片
newSlice := make([]int, len(slice))
copy(newSlice, slice)
// 模拟写入操作
slice = append(slice, id)
cond.Broadcast()
mu.Unlock()
}(i)
} else {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
for len(slice) == 0 {
cond.Wait()
}
// 复制切片
newSlice := make([]int, len(slice))
copy(newSlice, slice)
cond.Broadcast()
mu.Unlock()
}()
}
}
wg.Wait()
fmt.Println(slice)
}
- 原理:`sync.Cond`基于`sync.Mutex`,通过`Wait`方法使协程等待特定条件(如切片为空或不为空),`Broadcast`方法通知其他等待的协程,用于更复杂的读写协调场景,避免不必要的等待和竞争。