面试题答案
一键面试- 原因解释:
- 互斥锁:
sync.Mutex
是一种简单的锁机制,同一时间只允许一个Goroutine获取锁进行操作。在缓存系统中,频繁的读取操作意味着大量的Goroutine会竞争锁,如果使用互斥锁,每次读取都需要获取锁,这会导致读操作的并发性能严重下降,因为读操作本身并不会修改数据,多个读操作同时进行不会产生数据冲突。 - 读写锁:
sync.RWMutex
区分了读锁和写锁。多个Goroutine可以同时获取读锁进行读取操作,只有当有Goroutine需要写入数据时,才需要获取写锁,并且获取写锁时会阻止其他所有读和写操作。这就大大提高了读操作的并发性能,非常适合缓存系统这种读多写少的场景。
- 互斥锁:
- 具体实现代码:
package main
import (
"fmt"
"sync"
)
type Cache struct {
data map[string]interface{}
lock sync.RWMutex
}
// Get 获取缓存数据
func (c *Cache) Get(key string) (interface{}, bool) {
c.lock.RLock()
defer c.lock.RUnlock()
value, exists := c.data[key]
return value, exists
}
// Set 设置缓存数据
func (c *Cache) Set(key string, value interface{}) {
c.lock.Lock()
defer c.lock.Unlock()
if c.data == nil {
c.data = make(map[string]interface{})
}
c.data[key] = value
}
func main() {
cache := Cache{}
var wg sync.WaitGroup
// 模拟多个读操作
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
key := fmt.Sprintf("key%d", id)
value, exists := cache.Get(key)
if exists {
fmt.Printf("Goroutine %d read value: %v\n", id, value)
} else {
fmt.Printf("Goroutine %d key not found\n", id)
}
}(i)
}
// 模拟一个写操作
wg.Add(1)
go func() {
defer wg.Done()
cache.Set("key1", "value1")
fmt.Println("Write operation completed")
}()
wg.Wait()
}
在上述代码中:
Cache
结构体包含一个map
用于存储缓存数据,以及一个sync.RWMutex
用于保证并发安全。Get
方法使用RLock
读锁,允许多个Goroutine同时读取缓存数据。Set
方法使用Lock
写锁,在写入数据时会阻止其他读和写操作,确保数据的一致性。