面试题答案
一键面试在Go语言中,可以使用sync.Mutex
或sync.RWMutex
来确保对二维切片的读写操作的一致性,避免数据竞争和不一致问题。以下是两种解决方案:
使用sync.Mutex
sync.Mutex
提供了一种简单的互斥锁机制,用于保护共享资源。在对二维切片进行读写操作时,需要先获取锁,操作完成后释放锁。
package main
import (
"fmt"
"sync"
)
var (
twoDSlice [][]int
mu sync.Mutex
)
func writeData(data [][]int) {
mu.Lock()
twoDSlice = data
mu.Unlock()
}
func readData() [][]int {
mu.Lock()
defer mu.Unlock()
return twoDSlice
}
func main() {
var wg sync.WaitGroup
// 模拟写操作
wg.Add(1)
go func() {
defer wg.Done()
writeData([][]int{{1, 2}, {3, 4}})
}()
// 模拟读操作
wg.Add(1)
go func() {
defer wg.Done()
result := readData()
fmt.Println(result)
}()
wg.Wait()
}
使用sync.RWMutex
sync.RWMutex
提供了读写锁机制,允许多个读操作同时进行,但写操作必须独占。这种方式在读取操作频繁而写入操作较少的情况下性能更好。
package main
import (
"fmt"
"sync"
)
var (
twoDSlice [][]int
rwMu sync.RWMutex
)
func writeData(data [][]int) {
rwMu.Lock()
twoDSlice = data
rwMu.Unlock()
}
func readData() [][]int {
rwMu.RLock()
defer rwMu.RUnlock()
return twoDSlice
}
func main() {
var wg sync.WaitGroup
// 模拟写操作
wg.Add(1)
go func() {
defer wg.Done()
writeData([][]int{{1, 2}, {3, 4}})
}()
// 模拟读操作
wg.Add(1)
go func() {
defer wg.Done()
result := readData()
fmt.Println(result)
}()
wg.Wait()
}
在上述代码中:
writeData
函数在写入二维切片时,先获取锁(mu.Lock()
或rwMu.Lock()
),操作完成后释放锁(mu.Unlock()
或rwMu.Unlock()
)。readData
函数在读取二维切片时,获取读锁(rwMu.RLock()
),操作完成后释放读锁(rwMu.RUnlock()
)。如果使用sync.Mutex
,则和写操作一样获取普通锁。- 在
main
函数中,通过go
关键字启动多个并发的读写操作,并使用sync.WaitGroup
等待所有操作完成。
这两种方法都能有效地避免数据竞争和不一致问题,具体使用哪种方法取决于应用场景中读写操作的频率。如果读操作远多于写操作,建议使用sync.RWMutex
;如果读写操作频率相近,使用sync.Mutex
即可。