在Go1.9之前,go自带的map不是并发安全的,也就是说,我们需要自己再封装一层,给map加上把读写锁,比如像下面这样:
type MapWithLock struct {
sync.RWMutex
M map[string]Kline
}
用MapWithLock的读写锁去控制map的并发安全。
但是到了Go1.9发布,它有了一个新的特性,那就是sync.map,它是原生支持并发安全的map,不过它的用法和以前我们熟悉的map完全不一样,主要还是因为sync.map封装了更为复杂的数据结构,以实现比之前加锁map更优秀的性能。
使用
var mySMap sync.Map
先声明
mySMap.Store(exchangeEntity.Exchange, exchangeEntity.ExchangeCnName) //业务逻辑,其实两个都是string类型
这个相当于是写map,第一个参数是key,第二个参数是value
func GetMySMapValue(tradingPlace string) string {
value, ok := mySMap.Load(tradingPlace)
if ok {
mySMapValue, valid := value.(string)
if valid {
return mySMapValue
} else {
logger.Debug("invalid type assertion error", value)
return ""
}
}
return ""
}
这里我对Load进行了一层封装,因为Load方法返回的是interface{}和bool,所以需要先判断是否存在这个key-value,然后再进行类型断言,所以封装起来对外部调用会更友好。
mySMap.Delete(exchangeEntity.Exchange)
删除比较简单,直接传进去想删除的key就可以了
mySMap.Range(func(key, value interface{}) bool {
tmpval, valid := value.(string)
if !valid {
logger.Debug("invalid type assertion error", value)
return true //返回true,则range下一个key
}
if tmpval.HotFlag == true { //业务逻辑,不用管
tmpkey, valid := key.(string)
if !valid {
logger.Debug("invalid type assertion error", key)
return true //返回true,则range下一个key
}
result = append(result, tmpkey) //业务逻辑,不用管
}
return true
})
注意sync.Map的Range依旧是无序的,我们需要传给Range方法一个函数对象,这个闭包函数接受key和value,返回bool,返回true则直接进行下一个循环,类似continue。返回false则直接终止Range,类似break。
Go 1.9源代码中提供了性能的测试: map_bench_test.go、map_reference_test.go
相比较以前的解决方案,性能多少回有些提升,在性能瓶颈的地方,可以考虑使用sync.Map来代替原来方案。
BenchmarkHitAll/*sync.RWMutexMap-4 20000000 83.8 ns/op
BenchmarkHitAll/*sync.Map-4 30000000 59.9 ns/op
BenchmarkHitAll_WithoutPrompting/*sync.RWMutexMap-4 20000000 96.9 ns/op
BenchmarkHitAll_WithoutPrompting/*sync.Map-4 20000000 64.1 ns/op
BenchmarkHitNone/*sync.RWMutexMap-4 20000000 79.1 ns/op
BenchmarkHitNone/*sync.Map-4 30000000 43.3 ns/op
BenchmarkHit_WithoutPrompting/*sync.RWMutexMap-4 20000000 81.5 ns/op
BenchmarkHit_WithoutPrompting/*sync.Map-4 30000000 44.0 ns/op
BenchmarkUpdate/*sync.RWMutexMap-4 5000000 328 ns/op
BenchmarkUpdate/*sync.Map-4 10000000 146 ns/op
BenchmarkUpdate_WithoutPrompting/*sync.RWMutexMap-4 5000000 336 ns/op
BenchmarkUpdate_WithoutPrompting/*sync.Map-4 5000000 324 ns/op
BenchmarkDelete/*sync.RWMutexMap-4 10000000 155 ns/op
BenchmarkDelete/*sync.Map-4 30000000 55.0 ns/op
BenchmarkDelete_WithoutPrompting/*sync.RWMutexMap-4 10000000 173 ns/op
BenchmarkDelete_WithoutPrompting/*sync.Map-4 10000000 147 ns/op