Golang 原子操作的应用及踩坑

背景

gener_url常驻内存获取配置优化

常驻内存的相关请见博文 Golang 常驻内存学习并使用

 

优化原因

由于需要将3个redis-key改为常驻内存,一开始我是逐个key获取并判断err,有问题则终止本次操作,虽然常驻内存的启动仅在项目启动时、每分钟一次更新,但我希望尽量不写冗余操作,所以做了如下优化:

  1. 使用pipeline处理key
  2. 将之前为了处理map类型与unsafe指针转换而额外引入的结构体指针给清除掉。

 

原子操作

golang中会出现并发读取变量,那么为了防止数据污染,我们通常使用锁机制来处理,这也是其他语言常用的手法,但是golang内置了一套方法—原子操作,是基于底层的,可以彻底的避开锁机制,以达到提升性能的目的,最关键的是原子操作同一时刻只允许一个goroutin对变量进行操纵,所以原子操作是并发安全的。原子操作可以操纵多种类型的数据,也包括操纵指针,具体可以看文档:https://studygolang.com/pkgdoc

 

unsafe包

顾名思义,一种非安全操作,官方有下列四种描述:

任何类型的指针都可以被转化为Pointer

Pointer可以被转化为任何类型的指针

uintptr可以被转化为Pointer

Pointer可以被转化为uintptr

详情请见文章  https://studygolang.com/articles/18436

 

过程

1.使用pipeline处理key, 过程很简单,将之前逐个获取key的方式包在pipeline里,最后执行一个exec即可, 这里要注意一点,pipeline获取不存在的key时,结果会返回redis.nil 而不是nil ,所以我们要判断err时要注意去除redis.nil的影响。

2.处理指针问题,这里涉及到原子操作的指针类型操作,这里我们要知道,原子操作里存储一个变量,我们使用store语法,获取变量我们使用load语法,交换变量我们使用swap语法,这些在文档里都有,本次优化我是吧之前为了让map类型与unsafe包的pointer相互转换,而额外引用了一个结构指针,当时是吧unsafe.poniter强转为map类型不成功,以为无法转换,所以又包了一层结构体才实现功能。后来查阅大量资料发现,unsafe.pointer指针是支持转换为其余各种类型的,其中也包括map,后来我review代码,发现是我map类型变量指针用错了,正确用法是*(*map), 而我之前是用的**map, 所以导致转换不成功。该用正确指针形式后,是没有问题的,代码如下

 

 

总结:

1.获取多个redisKey的时候 ,能用管道操作就用管道操作,尽可能的给redis减压,积少成多,在大促期间能够有效的减轻redis压力(此处频率并不高,只是为了联系redis的pipeline操作)

2.原子操作中的指针转换,unsafe.pointer支持与其余各种类型转换,如果没有转换成功,可能是指针使用有误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值