Golang 开源项目cache2go 解读

栏目: Go · 发布时间: 7年前

内容简介:参考

参考

启航 - cache2 go 源码分析

cache2go - cachetable源码分析

cache2go源码最后一讲 - examples

这3篇博客写得很详细,下面只做部分重点摘抄

一、简介 https://github.com/muesli/cache2go

这是一个在github上开源的项目,原作者这样介绍:

Concurrency-safe golang caching library with expiration capabilities.

看懂了吗?简单说就是有心跳机制的并发安全的go语言缓存库。ok,下面我们要分析的这个项目是一个缓存库,并且有2大特性,并发安全和心跳机制!

Golang 开源项目cache2go 解读

image.png

二、CacheItem

type CacheItem struct {
    sync.RWMutex

    // The item's key.
    key interface{}
    // The item's data.
    data interface{}
    // How long will the item live in the cache when not being accessed/kept alive.
    lifeSpan time.Duration

    // Creation timestamp.
    createdOn time.Time
    // Last access timestamp.
    accessedOn time.Time
    // How often the item was accessed.
    accessCount int64

    // Callback method triggered right before removing the item from the cache
    aboutToExpire func(key interface{})
}

1.结构体中使用了匿名的读写锁sync.RWMutex,可以参考

Golang 学习笔记四 结构体

Golang 学习笔记十 并发编程 锁

注意这个开源项目使用读锁时,经常是用临时变量缓存一下,然后就解锁了。

2.lifeSpan time.Duration 这个是寿命,从后面可知,如果为0表示无限寿命

3.然后就是创建时间,最后访问时间,访问次数,被删除时触发的回调。

4.在 Golang 学习笔记六 函数和方法的区别 介绍了函数和方法。

CacheItem就一个NewCacheItem()函数,设置了一些默认值。

CacheItem的方法定义,一共8个

Golang 开源项目cache2go 解读

image.png

看下最后一个:

// SetAboutToExpireCallback configures a callback, which will be called right
// before the item is about to be removed from the cache.
func (item *CacheItem) SetAboutToExpireCallback(f func(interface{})) {
    item.Lock()
    defer item.Unlock()
    item.aboutToExpire = f
}

这就是在设置那个回调属性了,这个方法的形参是f func(interface{}),也就是说形参名为f,形参类型是func(interface{}),这是一个函数类型,这个函数类型的参数是一个interface{},也就是空接口,因为任意类型都可以被认为实现了空接口,所以这里可以接收任意类型的实参。也就是说f的类型是一个可以接收任意类型参数的函数类型。

在callbacks.go的例子中,显示了使用方式:

// Caching a new item that expires in 3 seconds
res = cache.Add("anotherKey", 3*time.Second, "This is another test")
// This callback will be triggered when the item is about to expire
res.SetAboutToExpireCallback(func(key interface{}) {
    fmt.Println("About to expire:", key.(string))
})

设置了寿命是3秒钟,运行后也能看到,3秒后自己失效了,打印出 About to expire: anotherKey

注意 func (item *CacheItem) SetAboutToExpireCallback(f func(interface{})) { 的参数里,是没有形参名称的,因为不需要,看个更简单的例子:

func main() {
    var show func(int)
    show = func(num int) { fmt.Println(num) }
    show(123)
}

另外,在使用示例中,对key使用了类型断言,是因为示例使用了字符串做key。实际上key是个接口类型,可以是任意类型。

在cachetable.go中,deleteInternal方法中会调用item的aboutToExpire

if r.aboutToExpire != nil {
        r.aboutToExpire(key)
    }

三、cachetable.go

1.Add和NotFoundAdd方法

NotFoundAdd会根据key判断是不是已经有数据了,如果没有的话,也会添加。两者都会调用addInternal。

2.addInternal

expDur := table.cleanupInterval
// If we haven't set up any expiration check timer or found a more imminent item.
if item.lifeSpan > 0 && (expDur == 0 || item.lifeSpan < expDur) {
    table.expirationCheck()
}

lifeSpan如果为0,相当于无限寿命,不会触发过期时间的检查。lifeSpan大于0时,这个cleanupInterval第一次使用时,默认是0,也就是还没设置检查时间间隔。那么会立即触发时间检查。而如果已经有检查时间间隔,则看一下新添加的item如果寿命小于这个间隔,也要立即触发检查。

3.expirationCheck

开始检查时,如果有cleanupTimer,要先停掉。

然后就是遍历一下items,逐项检查。有过期的,就调用table.deleteInternal(key)。没过期的,就计算一下还差多久要过期,然后使用smallestDuration记录一下最小的那个快过期时间,作为下次的检查时间。

如果下次检查时间大于0,则启动一个cleanupTimer,到时间后,重新执行expirationCheck

// Setup the interval for the next cleanup run.
table.cleanupInterval = smallestDuration
if smallestDuration > 0 {
    table.cleanupTimer = time.AfterFunc(smallestDuration, func() {
        go table.expirationCheck()
    })
}

这里有go关键字,并不是循环启动goroutine,启动一个新的goroutine后当前goroutine会退出,这里不会引起goroutine泄漏。

4.func (table CacheTable) Value(key interface{}, args ...interface{}) ( CacheItem, error) {

这里的args是在loadData != nil时,给loadData使用的。

if loadData != nil {
    item := loadData(key, args...)
    if item != nil {
        table.Add(key, item.lifeSpan, item.data)
        return item, nil
    }

    return nil, ErrKeyNotFoundOrLoadable
}

从dataloader.go示例中,可以看出,loadData可以在缓存中没有数据中,从数据库、网络、文件中读取。

5.清空

// Flush deletes all items from this cache table.
func (table *CacheTable) Flush() {
    table.Lock()
    defer table.Unlock()

    table.log("Flushing table", table.name)

    table.items = make(map[interface{}]*CacheItem)
    table.cleanupInterval = 0
    if table.cleanupTimer != nil {
        table.cleanupTimer.Stop()
    }
}

从注释可以看出来这个函数就是清空数据的作用,实现方式简单粗暴,让table的items属性指向一个新建的空map,cleanup操作对应的时间间隔设置为0,并且计时器停止。这里也可以得到cleanupInterval为0是什么场景,也就是说0不是代表清空操作死循环,间隔0秒就执行,而是表示不需要操作,缓存表还是空的。

6.排序,涉及到sort.Sort的玩法

1// MostAccessed returns the most accessed items in this cache table
 2//【访问频率高的count条item全部返回】
 3func (table *CacheTable) MostAccessed(count int64) []*CacheItem {
 4    table.RLock()
 5    defer table.RUnlock()
 6    //【这里的CacheItemPairList是[]CacheItemPair类型,是类型不是实例】
 7    //【所以p是长度为len(table.items)的一个CacheItemPair类型的切片类型
 8    p := make(CacheItemPairList, len(table.items))
 9    i := 0
10    //【遍历items,将Key和AccessCount构造成CacheItemPair类型数据存入p切片】
11    for k, v := range table.items {
12        p[i] = CacheItemPair{k, v.accessCount}
13        i++
14    }
15    //【这里可以直接使用Sort方法来 排序 是因为CacheItemPairList
        //实现了sort.Interface接口,也就是Swap,Len,Less三个方法】
16    //【但是需要留意上面的Less方法在定义的时候把逻辑倒过来了,导致排序是从大到小的】
17    sort.Sort(p)
18
19    var r []*CacheItem
20    c := int64(0)
21    for _, v := range p {
22        //【控制返回值数目】
23        if c >= count {
24            break
25        }
26
27        item, ok := table.items[v.Key]
28        if ok {
29            //【因为数据是按照访问频率从高到底排序的,所以可以从第一条数据开始加】
30            r = append(r, item)
31        }
32        c++
33    }
34
35    return r
36}

四、cache.go

func Cache(table string) *CacheTable {
    mutex.RLock()
    t, ok := cache[table]
    mutex.RUnlock()

    if !ok {
        mutex.Lock()
        t, ok = cache[table]
        // Double check whether the table exists or not.
        if !ok {
            t = &CacheTable{
                name:  table,
                items: make(map[interface{}]*CacheItem),
            }
            cache[table] = t
        }
        mutex.Unlock()
    }

    return t
}

注意这里锁的二次检查


以上所述就是小编给大家介绍的《Golang 开源项目cache2go 解读》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Security Testing Cookbook

Web Security Testing Cookbook

Paco Hope、Ben Walther / O'Reilly Media / 2008-10-24 / USD 39.99

Among the tests you perform on web applications, security testing is perhaps the most important, yet it's often the most neglected. The recipes in the Web Security Testing Cookbook demonstrate how dev......一起来看看 《Web Security Testing Cookbook》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具