当前位置: 首页 > 工具软件 > go-cache > 使用案例 >

Golang 扩展 go-cache

燕正德
2023-12-01

简介

Github地址

go-cache 是一个基于内存的、高速的,存储k-v格式的缓存工具。它适用于运行在单台机器上的应用程序,可以存储任何数据类型的值,并可以被多个goroutine安全地使用。

虽然go-cache 不打算用作持久数据存储,但是可以将整个缓存数据保存到文件(或任何io.Reader/Writer)中,并且能快速从中指定数据源加载,快速恢复状态。

安装

go get github.com/patrickmn/go-cache

使用

import (
	"fmt"
	"github.com/patrickmn/go-cache"
	"time"
)

func main() {

	// 默认过期时间为5min,每10min清理一次过期缓存
	c := cache.New(5*time.Minute, 10*time.Minute)

	// 设置key-value,并设置为默认过期时间
	c.Set("foo", "bar", cache.DefaultExpiration)

	// 设置一个不会过期的key,该key不会自动删除,重新更新key或者使用c.Delete("baz")
	c.Set("baz", 42, cache.NoExpiration)

	// 从缓存获取对应key的值
	foo, found := c.Get("foo")
	if found {
		fmt.Println(foo)
	}

	// Since Go is statically typed, and cache values can be anything, type
	// assertion is needed when values are being passed to functions that don't
	// take arbitrary types, (i.e. interface{}). The simplest way to do this for
	// values which will only be used once--e.g. for passing to another
	// function--is:
	foo, found := c.Get("foo")
	if found {
		MyFunction(foo.(string))
	}

	// This gets tedious if the value is used several times in the same function.
	// You might do either of the following instead:
	if x, found := c.Get("foo"); found {
		foo := x.(string)
		// ...
	}
	// or
	var foo string
	if x, found := c.Get("foo"); found {
		foo = x.(string)
	}
	// ...
	// foo can then be passed around freely as a string

	// Want performance? Store pointers!
	c.Set("foo", &MyStruct, cache.DefaultExpiration)
	if x, found := c.Get("foo"); found {
		foo := x.(*MyStruct)
			// ...
	}
}

源码分析

有关defer的使用

defer是一个很强大的机制,尤其是在资源释放的场景特别适用。但是使用时要注意,defer是有不小的性能损耗,且过度使用后也会导致逻辑变复杂。go-cache源码中没有使用defer,也做了相应的注释。

func (c *cache) Set(k string, x interface{}, d time.Duration) {
	// "Inlining" of set
	var e int64
	if d == DefaultExpiration {
		d = c.defaultExpiration
	}
	if d > 0 {
		e = time.Now().Add(d).UnixNano()
	}
	c.mu.Lock()
	c.items[k] = Item{
		Object:     x,
		Expiration: e,
	}
	// TODO: Calls to mu.Unlock are currently not deferred because defer
	// adds ~200 ns (as of go1.)
	c.mu.Unlock()
}

有关SetFinalizer的使用

在Go中,finalizer函数是当对象不在被引用,对象被GC进程选中并从内存中移除的时候将其调用,有点类似析构函数。可以使用runtime.SetFinalizer函数向对象添加finalizer

func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
	c := newCache(de, m)
	// This trick ensures that the janitor goroutine (which--granted it
	// was enabled--is running DeleteExpired on c forever) does not keep
	// the returned C object from being garbage collected. When it is
	// garbage collected, the finalizer stops the janitor goroutine, after
	// which c can be collected.
	C := &Cache{c}
	if ci > 0 {
		runJanitor(c, ci)
		runtime.SetFinalizer(C, stopJanitor)
	}
	return C
}

参考

文档地址
golang defer使用需要注意
垃圾回收和 SetFinalizer
Go 性能优化技巧 10/10
go中的finalizer

 类似资料: