经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
beego解读Cache之MemoryCache
来源:cnblogs  作者:麻辣条  时间:2019/1/21 9:42:44  对本文有异议

beego 框架 cache 目录是 Go 实现的一个缓存管理器,是beego框架自带工具之一,当然,如果你只想使用 cache 而不是整个 beego 框架,可以选择性安装:

  1. go get github.com/astaxie/beego/cache

在我写这篇博文时, beego 版本是 v1.11.1 , cache 支持内存、文件、 memcache 、 redis、ssdb 。

使用例子:

  1. package main
  2. import (
  3. // 导入cache包
  4. "github.com/astaxie/beego/cache"
  5. "time"
  6. )
  7. func main() {
  8. /*
  9. bm, err := cache.NewCache("memcache", `{"conn":"127.0.0.1:11211"}`)//memcache
  10. bm, err := cache.NewCache("redis", `{"conn":":6039"}`)//redis
  11. bm, err := cache.NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`)
  12. */
  13. // 初始化一个内存的缓存管理器
  14. bm, err := cache.NewCache("memory", `{"interval":60}`)
  15. bm.Put("user", "张三", 10 * time.Second) //
  16. bm.Get("user")
  17. bm.IsExist("user")
  18. bm.Delete("user")
  19. }

cache 包定义了Cache接口,如下:

  1. // Cache interface contains all behaviors for cache adapter.
  2. // usage:
  3. // cache.Register("file",cache.NewFileCache) // this operation is run in init method of file.go.
  4. // c,err := cache.NewCache("file","{....}")
  5. // c.Put("key",value, 3600 * time.Second)
  6. // v := c.Get("key")
  7. //
  8. // c.Incr("counter") // now is 1
  9. // c.Incr("counter") // now is 2
  10. // count := c.Get("counter").(int)
  11. type Cache interface {
  12. // Get 函数通过键获取值。
  13. Get(key string) interface{}
  14. // GetMulti 是 Get 的一个批处理版本。
  15. GetMulti(keys []string) []interface{}
  16. // Put 函数设置存入一对键值和到期时间。
  17. Put(key string, val interface{}, timeout time.Duration) error
  18. // 通过键删除值.
  19. Delete(key string) error
  20. // 让键对应的值加1.
  21. Incr(key string) error
  22. // 让键对应的值减1.
  23. Decr(key string) error
  24. // 检查一个键是否存在.
  25. IsExist(key string) bool
  26. // 清空所有缓存.
  27. ClearAll() error
  28. // 根据配置启动一个gc协程。
  29. StartAndGC(config string) error
  30. }

cache.go文件定义了 Instance , Instance 是一个 function ,功能是创建一个Cache接口的实例。adapters是一个 map 用于注册实现了 Cache 的适配器。Register注册可用的适配器,如果被调用两次或者驱动为空,将 panic 。代码如下:

  1. type Instance func() Cache
  2. var adapters = make(map[string]Instance)
  3. func Register(name string, adapter Instance) {
  4. if adapter == nil {
  5. panic("cache: Register adapter is nil")
  6. }
  7. if _, ok := adapters[name]; ok {
  8. panic("cache: Register called twice for adapter " + name)
  9. }
  10. adapters[name] = adapter
  11. }

我们来先看内存缓存的实现方式:

1.MemoryCache memory,go

全局变量及结构

DefaultEvery 表示在内存中回收过期缓存项的时间,默认为 1 分钟。

  1. var DefaultEvery = 60

MemoryItem 用于保存基本内存缓存元素.

  1. type MemoryItem struct {
  2. val interface{}
  3. createdTime time.Time
  4. lifespan time.Duration
  5. }

MemoryCache 是一个内存管理适配器,它包含了一个读写锁(sync.RWMutex),使得 MemoryCache 具备并发安全性。

  1. type MemoryCache struct {
  2. sync.RWMutex
  3. dur time.Duration
  4. items map[string]*MemoryItem
  5. Every int // run an expiration check Every clock time
  6. }

方法及函数

init function 注册驱动名,其实就是一个map存取操作,见上面的 Register 函数。

  1. func init() {
  2. Register("memory", NewMemoryCache)
  3. }

NewMemoryCache 初始化一个内存缓存适配器,返回 Cache 接口,NewMemoryCache 实现了 Cache 接口。

  1. func NewMemoryCache() Cache {
  2. cache := MemoryCache{items: make(map[string]*MemoryItem)}
  3. return &cache
  4. }

Get 返回一个键在 MemoryCache 中的值, 如果该键不存在或到期,返回nil。

  1. func (bc *MemoryCache) Get(name string) interface{} {
  2. bc.RLock()
  3. defer bc.RUnlock()
  4. if itm, ok := bc.items[name]; ok {
  5. if itm.isExpire() {
  6. return nil
  7. }
  8. return itm.val
  9. }
  10. return nil
  11. }

GetMulti 传入一个键的 slice,返回slice中存在于缓存且没有过期的值.

  1. func (bc *MemoryCache) GetMulti(names []string) []interface{} {
  2. var rc []interface{}
  3. for _, name := range names {
  4. rc = append(rc, bc.Get(name))
  5. }
  6. return rc
  7. }

Put 向 MemoryCache 中存入一个键名位name ,值为 item 的缓存键值对并设置时间为 lifespan ,如果时间为 0 ,那么 item 将永远存在,除非用户主动删除或。

  1. func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {
  2. bc.Lock()
  3. defer bc.Unlock()
  4. bc.items[name] = &MemoryItem{
  5. val: value,
  6. createdTime: time.Now(),
  7. lifespan: lifespan,
  8. }
  9. return nil
  10. }

Delete 删除 MemoryCache 中键名为 name 的缓存.

  1. func (bc *MemoryCache) Delete(name string) error {
  2. bc.Lock()
  3. defer bc.Unlock()
  4. if _, ok := bc.items[name]; !ok {
  5. return errors.New("key not exist")
  6. }
  7. delete(bc.items, name)
  8. if _, ok := bc.items[name]; ok {
  9. return errors.New("delete key error")
  10. }
  11. return nil
  12. }

Incr 增加键名为 name 缓存的值,支持类型:int,int32,int64,uint,uint32,uint64.

  1. func (bc *MemoryCache) Incr(key string) error {
  2. bc.RLock()
  3. defer bc.RUnlock()
  4. itm, ok := bc.items[key]
  5. if !ok {
  6. return errors.New("key not exist")
  7. }
  8. switch itm.val.(type) {
  9. case int:
  10. itm.val = itm.val.(int) + 1
  11. case int32:
  12. itm.val = itm.val.(int32) + 1
  13. case int64:
  14. itm.val = itm.val.(int64) + 1
  15. case uint:
  16. itm.val = itm.val.(uint) + 1
  17. case uint32:
  18. itm.val = itm.val.(uint32) + 1
  19. case uint64:
  20. itm.val = itm.val.(uint64) + 1
  21. default:
  22. return errors.New("item val is not (u)int (u)int32 (u)int64")
  23. }
  24. return nil
  25. }

Decr 减少键名为 name 缓存的值,支持类型:int,int32,int64,uint,uint32,uint64,如果类型为 uint,uint32,uint64 且值为 0 时,会返回值小于0错误。

  1. func (bc *MemoryCache) Decr(key string) error {
  2. bc.RLock()
  3. defer bc.RUnlock()
  4. itm, ok := bc.items[key]
  5. if !ok {
  6. return errors.New("key not exist")
  7. }
  8. switch itm.val.(type) {
  9. case int:
  10. itm.val = itm.val.(int) - 1
  11. case int64:
  12. itm.val = itm.val.(int64) - 1
  13. case int32:
  14. itm.val = itm.val.(int32) - 1
  15. case uint:
  16. if itm.val.(uint) > 0 {
  17. itm.val = itm.val.(uint) - 1
  18. } else {
  19. return errors.New("item val is less than 0")
  20. }
  21. case uint32:
  22. if itm.val.(uint32) > 0 {
  23. itm.val = itm.val.(uint32) - 1
  24. } else {
  25. return errors.New("item val is less than 0")
  26. }
  27. case uint64:
  28. if itm.val.(uint64) > 0 {
  29. itm.val = itm.val.(uint64) - 1
  30. } else {
  31. return errors.New("item val is less than 0")
  32. }
  33. default:
  34. return errors.New("item val is not int int64 int32")
  35. }
  36. return nil
  37. }

IsExist 检查键为 name 的缓存是否存在.

  1. func (bc *MemoryCache) IsExist(name string) bool {
  2. bc.RLock()
  3. defer bc.RUnlock()
  4. if v, ok := bc.items[name]; ok {
  5. return !v.isExpire()
  6. }
  7. return false
  8. }

ClearAll 会清除所有缓存.

  1. func (bc *MemoryCache) ClearAll() error {
  2. bc.Lock()
  3. defer bc.Unlock()
  4. bc.items = make(map[string]*MemoryItem)
  5. return nil
  6. }

StartAndGC 开始周期性对缓存进行检查,如果缓存键值对过期,会被删除。

  1. func (bc *MemoryCache) StartAndGC(config string) error {
  2. var cf map[string]int
  3. json.Unmarshal([]byte(config), &cf)
  4. if _, ok := cf["interval"]; !ok {
  5. cf = make(map[string]int)
  6. cf["interval"] = DefaultEvery
  7. }
  8. dur := time.Duration(cf["interval"]) * time.Second
  9. bc.Every = cf["interval"]
  10. bc.dur = dur
  11. go bc.vacuum()
  12. return nil
  13. }

未导出函数及方法

  1. // 检查是否超时.
  2. func (bc *MemoryCache) vacuum() {
  3. bc.RLock()
  4. every := bc.Every
  5. bc.RUnlock()
  6. if every < 1 {
  7. return
  8. }
  9. for {
  10. <-time.After(bc.dur)
  11. if bc.items == nil {
  12. return
  13. }
  14. if keys := bc.expiredKeys(); len(keys) != 0 {
  15. bc.clearItems(keys)
  16. }
  17. }
  18. }
  19. // expiredKeys 返回到期的键名 slice.
  20. func (bc *MemoryCache) expiredKeys() (keys []string) {
  21. bc.RLock()
  22. defer bc.RUnlock()
  23. for key, itm := range bc.items {
  24. if itm.isExpire() {
  25. keys = append(keys, key)
  26. }
  27. }
  28. return
  29. }
  30. // clearItems 清空键名在 keys 内的缓存.
  31. func (bc *MemoryCache) clearItems(keys []string) {
  32. bc.Lock()
  33. defer bc.Unlock()
  34. for _, key := range keys {
  35. delete(bc.items, key)
  36. }
  37. }

后记

file、ssdb、memcache和redis实现都相似,file以文件方式储存每个键对应一个文件,文件内容为值的数据,用gob编码持久化。

原文链接:http://www.cnblogs.com/asp-poor-as-john/p/go_beego_cache_memorycache.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号