atomic.Value代替sync.RWMutex

laotoutou · · 776 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

记一次性能优化,读公司项目代码时候,发现好些使用sync.RWMutext的使用场景:项目启动时候对高频数据缓存到内存缓存中,同时每隔一段时间重新写一下这个缓存(用一个全局变量):

type cosCred struct {
    Cred []int64
    sync.RWMutex
}

var CosCred *cosCred

// 每分钟写一次
func InitCosCred() {
    CosCred = new(cosCred)
    CosCred.Cred, _ = GetGlobalCredData()
    go func() {
        for range time.NewTicker(10 * time.Minute).C {
            cred, err := GetGlobalCredData()
            if err != nil {
                continue
            }
            CosCred.Lock()
            CosCred.Cred = cred
            CosCred.Unlock()
        }
    }()
}

// 接口会并发读
func GetCosCred() []int64 {
    CosCred.RLock()
    defer CosCred.RUnlock()
    if CosCred.Cred == nil {
        return nil
    }
    resp := CosCred.Cred
    return resp
}

看到以上场景是一个协程写,接口并发读,而写的过程是直接修改变量的值(切片引用类型,修改了全局变量指向的底层数组),只是这一个写的过程,却要在每次读的时候加读锁,其实只要换成保证原子操作的变量赋值和读取就行了,使用atomic.Value

atomic.Value封装了一个interface{}类型的v变量,简单粗暴,同时提供了Load和Store原子操作,用于给v原子赋值和读取,简单修改下:


var CosCred atomic.Value

// 每分钟写一次
func InitCosCred() {
    data := GetGlobalCredData()
    CosCred.Store(data)
    go func() {
        for range time.NewTicker(10 * time.Minute).C {
            cred, err := GetGlobalCredData()
            if err != nil {
                continue
            }
            CosCred.Store(data)
        }
    }()
}

// 接口会并发读
func GetCosCred() []int64 {
    resp, _ := CosCred.Load().([]int64)
    return resp
}

原子操作由底层硬件支持,而锁则由操作系统的调度器实现。锁应当用来保护一段逻辑,对于一个变量更新的保护,原子操作通常会更有效率

关于atomic.Value有一篇不错的blog
https://blog.betacat.io/post/golang-atomic-value-exploration/


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:laotoutou

查看原文:atomic.Value代替sync.RWMutex

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

776 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传