最近收到了一个需求
需要不断的在一个data pool随机找到资料后,给前端显示新value
刚开始的做法是把资料全部存在DB内
然后再根据flag做where,之后再更新flag
但如此一来
DB虽说没被吃垮,但假设资料量持续增长,DB铁定会因为频繁的update给搞到爆掉
而且从目前评估起来,DB一分钟内高峰时会做到800-1000次update
听起来就不太妙XD
于是只把资料Load一次,改用本地cache去做操作
但也出现了一个问题
资料有n笔,我在本地也要做O(n)次搜寻,然后再去改flag
最棒的是这个handler有複数个routing在执行,在加上API也会操作到
从一般的Lock改用RWLock,API还是一样会hang在那边到timeout
但直到最后我想到了sync.Map
没有race condtionkey-value的资料结构,只要O(1)就能解决问题,还能简化资料栏位map本身就是无顺序结构,还能来拿当随机使用然后只要用一个sync.Map当作cache pool,资料失效就丢回来pool,资料生效就从pool删除一开始的做法
func SelectDataBaseData(){}func HandleRandomPickData(){ // Do random pick data from SelectDataBaseData() for index:=range afterPickData{ UpdateDataStatus() }}func HandleTimeOutData(){ for index:=range afterPickData{ UpdateDataStatus() }}func UpdateDataStatus(){ // Do data update status to database}
二次做法
var datas []DataStructure{}var mux sync.RWMutexfunc InitializeCacheData(){ selectData:=SelectDataBaseData() for _,data:=range selectData{ datas = append(datas,data) }}func HandleRandomPickData(){ // Do random pick data from datas for i:=range afterPickData{ for j:=range datas{ if datas[j].key == afterPickData[i].key{ mux.Lock() datas[j].status = 1 mux.Unlock } } }}func HandleTimeOutData(){ // Do random and pick data for i:=range afterPickData{ for j:=range datas{ if datas[j].key == afterPickData[i].key{ mux.Lock() datas[j].status = 0 mux.Unlock } } }}
改良版
var mp sync.Map{}func InitializeCacheData(){ datas:=SelectDataBaseData() for _,data:=range datas { mp.Store(data.key,data.value) }}func HandleRandomPickData(){ count:= 0 mp.Range(func(key interface{}, value interface{}) bool { if count == 10 { return false } PickKey:=key.(T) PickValue:=value.(T) mp.Delete(key.(T)) count++ return true })}func HandleTimeOutData(){ data:=GetTimeOutValue() for index:=ramge data{ mp.Store(data[i].Key,data[i].Value) }}
总结
在闲闲没事的时候总是会灵光一闪
想到一个做pool的办法直接解决所有问题
还能利用资料结构的特性带来时间上的优势
加上package还有改良过对race condition的影响
只有最好用没有更好用XD