面试题答案
一键面试数据一致性问题分析
当多个 goroutine 同时对一个 Go 切片进行读写操作时,可能会出现以下数据一致性问题:
- 竞态条件(Race Condition):多个 goroutine 同时读取和写入切片,可能导致读取到不一致的数据。例如,一个 goroutine 正在写入切片的某个位置,而另一个 goroutine 同时读取该位置,可能会读取到部分修改的数据。
- 数据覆盖:多个 goroutine 同时写入切片的相同位置,会导致数据覆盖,丢失之前的写入结果。
通过 Go 语言特性保证数据一致性
Go 语言提供了 sync
包来解决并发编程中的数据一致性问题。常用的方法有:
- 互斥锁(Mutex):使用
sync.Mutex
来保护对切片的读写操作。在读取或写入切片之前,先获取锁,操作完成后释放锁。这样可以确保同一时间只有一个 goroutine 能够访问切片,避免竞态条件和数据覆盖。 - 读写锁(RWMutex):如果读操作远多于写操作,可以使用
sync.RWMutex
。读操作时可以多个 goroutine 同时进行,而写操作时会独占锁,防止其他读写操作。
示例场景及解决方案代码
假设我们有一个简单的场景,多个 goroutine 向一个切片中添加数据,同时有其他 goroutine 读取切片中的数据。
package main
import (
"fmt"
"sync"
)
var (
dataSlice []int
mu sync.Mutex
)
func writeData(wg *sync.WaitGroup, value int) {
defer wg.Done()
mu.Lock()
dataSlice = append(dataSlice, value)
mu.Unlock()
}
func readData(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
fmt.Println("Read data:", dataSlice)
mu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go writeData(&wg, i)
}
for i := 0; i < 3; i++ {
wg.Add(1)
go readData(&wg)
}
wg.Wait()
}
在这个示例中:
- 我们定义了一个全局的
dataSlice
切片和一个sync.Mutex
实例mu
。 writeData
函数负责向切片中添加数据,在操作前获取锁,操作后释放锁。readData
函数负责读取切片数据,同样在操作前后获取和释放锁。- 在
main
函数中,启动多个 goroutine 进行写入和读取操作,并使用sync.WaitGroup
等待所有 goroutine 完成。
这样通过使用互斥锁,我们保证了对切片的读写操作是线程安全的,避免了数据一致性问题。如果读操作较多,可以将 sync.Mutex
替换为 sync.RWMutex
,并在 readData
函数中使用读锁(mu.RLock()
和 mu.RUnlock()
)来提高并发性能。