读写锁(sync.RWMutex
)适用场景
- 读多写少场景:当对数据结构的读操作频率远高于写操作时,优先选择读写锁。因为读写锁允许多个读操作同时进行,不会相互阻塞,只有写操作会独占资源,这样可以大大提高并发读的效率。例如,一个提供股票实时行情的系统,大量用户会频繁读取股票价格,但只有少数情况下会更新股票价格。
GoMutex(sync.Mutex
)适用场景
- 读写操作频率相近或写多场景:如果读写操作频率相近,或者写操作频率高于读操作,使用普通的互斥锁(
sync.Mutex
)更为合适。因为读写锁在写操作时会阻塞所有读操作,若写操作频繁,使用读写锁反而会因频繁的锁切换降低性能。例如,一个在线投票系统,投票操作(写)和查看当前票数(读)频率相近,此时普通互斥锁能更好地保证数据一致性和性能。
在复杂并发数据结构(带有缓存的数据库查询结果集)中的应用
- 读多写少:
假设缓存的数据库查询结果集主要用于快速读取,只有在数据库数据更新时才会更新缓存。比如一个新闻网站的文章缓存,用户大量读取文章内容,但文章更新频率较低。这种情况下,使用读写锁。
package main
import (
"fmt"
"sync"
)
type CachedResultSet struct {
data map[string]interface{}
rwLock sync.RWMutex
}
func (c *CachedResultSet) Read(key string) (interface{}, bool) {
c.rwLock.RLock()
defer c.rwLock.RUnlock()
value, exists := c.data[key]
return value, exists
}
func (c *CachedResultSet) Write(key string, value interface{}) {
c.rwLock.Lock()
defer c.rwLock.Unlock()
if c.data == nil {
c.data = make(map[string]interface{})
}
c.data[key] = value
}
- 读写相近或写多:
若缓存的更新较为频繁,比如实时监控系统中缓存的传感器数据,传感器数据更新频率高且监控端也会频繁读取。这时用普通互斥锁。
package main
import (
"fmt"
"sync"
)
type CachedResultSet struct {
data map[string]interface{}
lock sync.Mutex
}
func (c *CachedResultSet) Read(key string) (interface{}, bool) {
c.lock.Lock()
defer c.lock.Unlock()
value, exists := c.data[key]
return value, exists
}
func (c *CachedResultSet) Write(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
}