go實(shí)現(xiàn)一個(gè)內(nèi)存緩存系統(tǒng)的示例代碼
面試內(nèi)容:
- 支持設(shè)定過(guò)期時(shí)間,精度到秒
- 支持設(shè)定最大內(nèi)存,當(dāng)內(nèi)存超出時(shí)做出合適的處理
- 支持并發(fā)安全
- 要求按照以下接口實(shí)現(xiàn)
SetMemory(size string) bool Set(key string, val interface{}, expire time.Duration) bool Get(key string) (interface{}, bool) Del(key string) bool Exists(key string) bool Flush() bool Keys() int64
下面為具體實(shí)現(xiàn)代碼:
接口
package cache import "time" type Cache interface { SetMemory(size string) bool Set(key string, val interface{}, expire time.Duration) bool Get(key string) (interface{}, bool) Del(key string) bool Exists(key string) bool Flush() bool Keys() int64 }
實(shí)現(xiàn)類
package cache import ( "fmt" "sync" "time" ) type MemCache struct { //最大內(nèi)存 maxMemorySize int64 // 當(dāng)前已使用的內(nèi)存 currMemorySize int64 // 最大內(nèi)存字符串表示 maxMemorySizeStr string // 緩存鍵值對(duì) values map[string]*memCacheValue // 讀寫(xiě)鎖 lock sync.RWMutex //設(shè)置清除過(guò)期緩存的時(shí)間間隔 clearExpireTime time.Duration } type memCacheValue struct { //value 值 val interface{} // 過(guò)期時(shí)間 expireTime time.Time //有效時(shí)間 expire time.Duration //value 大小 size int64 } func NewMemCache() Cache { mc := &MemCache{ clearExpireTime: time.Second * 10, values: make(map[string]*memCacheValue), } go mc.clearExpireItm() return mc } // SetMemory size 1KB 100KB 1M 2M 1GB func (mc *MemCache) SetMemory(size string) bool { mc.maxMemorySize, mc.maxMemorySizeStr = ParseSize(size) return true } // Set 設(shè)置緩存 func (mc *MemCache) Set(key string, val interface{}, expire time.Duration) bool { mc.lock.Lock() defer mc.lock.Unlock() v := &memCacheValue{val: val, expireTime: time.Now().Add(expire), expire: expire, size: GetValSize(val)} //mc.values[key] = v mc.del(key) mc.add(key, v) if mc.currMemorySize > mc.maxMemorySize { mc.del(key) panic(fmt.Sprintf("max memory size %d", mc.maxMemorySize)) } return true } func (mc *MemCache) get(key string) (*memCacheValue, bool) { val, ok := mc.values[key] return val, ok } func (mc *MemCache) del(key string) { tmp, ok := mc.get(key) if ok && tmp != nil { mc.currMemorySize -= tmp.size delete(mc.values, key) } } func (mc *MemCache) add(key string, val *memCacheValue) { mc.values[key] = val mc.currMemorySize += val.size } // Get 獲取緩存值 func (mc *MemCache) Get(key string) (interface{}, bool) { mc.lock.RLock() defer mc.lock.RUnlock() mcv, ok := mc.get(key) if ok { if mcv.expire != 0 && mcv.expireTime.Before(time.Now()) { mc.del(key) return nil, false } return mcv.val, ok } return nil, false } // Del 刪除緩存值 func (mc *MemCache) Del(key string) bool { mc.lock.Lock() defer mc.lock.Unlock() mc.del(key) return true } func (mc *MemCache) Exists(key string) bool { mc.lock.RLock() defer mc.lock.RUnlock() _, ok := mc.get(key) return ok } func (mc *MemCache) Flush() bool { mc.lock.Lock() defer mc.lock.Unlock() mc.values = make(map[string]*memCacheValue, 0) mc.currMemorySize = 0 return true } func (mc *MemCache) Keys() int64 { mc.lock.RLock() defer mc.lock.RUnlock() return int64(len(mc.values)) } func (mc *MemCache) clearExpireItm() { ticker := time.NewTicker(mc.clearExpireTime) defer ticker.Stop() for { select { case <-ticker.C: for key, v := range mc.values { if v.expire != 0 && time.Now().After(v.expireTime) { mc.lock.Lock() mc.del(key) mc.lock.Unlock() } } } } } // //var Cache = NewMemCache() // //func Set(key string, val interface{}) bool { // // return false //}
工具類
package cache import ( "log" "regexp" "strconv" "strings" ) const ( B = 1 << (iota * 10) KB MB GB TB PB ) func ParseSize(size string) (int64, string) { //默認(rèn)大小為 100M re, _ := regexp.Compile("[0-9]+") unit := string(re.ReplaceAll([]byte(size), []byte(""))) num, _ := strconv.ParseInt(strings.Replace(size, unit, "", 1), 10, 64) unit = strings.ToUpper(unit) var byteNum int64 = 0 switch unit { case "B": byteNum = num break case "KB": byteNum = num * KB break case "MB": byteNum = num * MB break case "GB": byteNum = num * GB break case "TB": byteNum = num * TB break case "PB": byteNum = num * PB break default: num = 0 byteNum = 0 } if num == 0 { log.Println("ParseSize 僅支持B,KB,MB,GB,TB,PB") num = 100 * MB byteNum = num unit = "MB" } sizeStr := strconv.FormatInt(num, 10) + unit return byteNum, sizeStr } func GetValSize(val interface{}) int64 { return 0 }
代理類
package server import ( "go_lang_pro/cache" "time" ) type cacheServer struct { memCache cache.Cache } func NewMemoryCache() *cacheServer { return &cacheServer{ memCache: cache.NewMemCache(), } } func (cs *cacheServer) SetMemory(size string) bool { return cs.memCache.SetMemory(size) } func (cs *cacheServer) Set(key string, val interface{}, expire ...time.Duration) bool { expirets := time.Second * 0 if len(expire) > 0 { expirets = expire[0] } return cs.memCache.Set(key, val, expirets) } func (cs *cacheServer) Get(key string) (interface{}, bool) { return cs.memCache.Get(key) } func (cs *cacheServer) Del(key string) bool { return cs.memCache.Del(key) } func (cs *cacheServer) Exists(key string) bool { return cs.memCache.Exists(key) } func (cs *cacheServer) Flush() bool { return cs.memCache.Flush() } func (cs *cacheServer) Keys() int64 { return cs.memCache.Keys() }
main 方法
package main import ( "go_lang_pro/cache" "time" ) func main() { cache := cache.NewMemCache() cache.SetMemory("100MB") cache.Set("int", 1, time.Second) cache.Set("bool", false, time.Second) cache.Set("data", map[string]interface{}{"a": 1}, time.Second) cache.Get("int") cache.Del("int") cache.Flush() cache.Keys() }
到此這篇關(guān)于go實(shí)現(xiàn)一個(gè)內(nèi)存緩存系統(tǒng)的示例代碼的文章就介紹到這了,更多相關(guān)go 內(nèi)存緩存系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
聊聊go xorm生成mysql的結(jié)構(gòu)體問(wèn)題
這篇文章主要介紹了go xorm生成mysql的結(jié)構(gòu)體問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2022-03-03Golang基于epoll實(shí)現(xiàn)最簡(jiǎn)單網(wǎng)絡(luò)通信框架
這篇文章主要為大家詳細(xì)介紹了Golang如何基于epoll實(shí)現(xiàn)最簡(jiǎn)單網(wǎng)絡(luò)通信框架,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)學(xué)習(xí)2023-06-06簡(jiǎn)單高效!Go語(yǔ)言封裝二級(jí)認(rèn)證功能實(shí)現(xiàn)
本文將介紹如何使用Go語(yǔ)言封裝二級(jí)認(rèn)證功能,實(shí)現(xiàn)簡(jiǎn)單高效的用戶認(rèn)證流程,二級(jí)認(rèn)證是一種安全措施,要求用戶在登錄后進(jìn)行額外的身份驗(yàn)證,以提高賬戶安全性,2023-10-10詳解go如何使用xorm在執(zhí)行前改寫(xiě)?SQL
這篇文章主要為大家介紹了詳解go如何使用xorm在執(zhí)行前改寫(xiě)SQL的實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Golang 實(shí)現(xiàn)復(fù)制文件夾同時(shí)復(fù)制文件
這篇文章主要介紹了Golang 實(shí)現(xiàn)復(fù)制文件夾同時(shí)復(fù)制文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12Go語(yǔ)言入門(mén)之基礎(chǔ)語(yǔ)法和常用特性解析
這篇文章主要給大家講解了Go語(yǔ)言的基礎(chǔ)語(yǔ)法和常用特性解析,比較適合入門(mén)小白,文中通過(guò)代碼示例介紹的非常詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,需要的朋友可以參考下2023-07-07Golang中json和jsoniter的區(qū)別使用示例
這篇文章主要介紹了Golang中json和jsoniter的區(qū)別使用示例,本文給大家分享兩種區(qū)別,結(jié)合示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2023-12-12