使用Go1.9的sync.map

在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

先声明

Store方法

mySMap.Store(exchangeEntity.Exchange, exchangeEntity.ExchangeCnName)  //业务逻辑,其实两个都是string类型

这个相当于是写map,第一个参数是key,第二个参数是value

Load方法

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,然后再进行类型断言,所以封装起来对外部调用会更友好。

Delete方法

mySMap.Delete(exchangeEntity.Exchange)

删除比较简单,直接传进去想删除的key就可以了

Range方法

    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。

sync.Map性能

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

你可能感兴趣的:(golang)