Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

gcache模块默认提供的是一个高速的内存缓存,操作效率非常高效,CPU性能损耗在ns纳秒级别。

示例1,基本使用

package main

import (
    "fmt"
    "github.com/gogf/gf/os/gcache"
)

func main() {
    // 创建一个缓存对象,
    // 当然也可以便捷地直接使用gcache包方法
    c := gcache.New()

    // 设置缓存,不过期
    c.Set("k1", "v1", 0)

    // 获取缓存
    v, _ := c.Get("k1")
    fmt.Println(v)

    // 获取缓存大小
    n, _ := c.Size()
    fmt.Println(n)

    // 缓存中是否存在指定键名
    b, _ := c.Contains("k1")
    fmt.Println(b)

    // 删除并返回被删除的键值
    fmt.Println(c.Remove("k1"))

    // 关闭缓存对象,让GC回收资源
    c.Close()
}

执行后,输出结果为:

v1
1
true
v1

示例2,缓存控制

package main

import (
    "fmt"
    "github.com/gogf/gf/os/gcache"
    "time"
)

func main() {
    // 当键名不存在时写入,设置过期时间1000毫秒
    gcache.SetIfNotExist("k1", "v1", 1000*time.Millisecond)

    // 打印当前的键名列表
    keys, _ := gcache.Keys()
    fmt.Println(keys)

    // 打印当前的键值列表
    values, _ := gcache.Values()
    fmt.Println(values)

    // 获取指定键值,如果不存在时写入,并返回键值
    v, _ := gcache.GetOrSet("k2", "v2", 0)
    fmt.Println(v)

    // 打印当前的键值对
    data1, _ := gcache.Data()
    fmt.Println(data1)

    // 等待1秒,以便k1:v1自动过期
    time.Sleep(time.Second)

    // 再次打印当前的键值对,发现k1:v1已经过期,只剩下k2:v2
    data2, _ := gcache.Data()
    fmt.Println(data2)
}

执行后,输出结果为:

[k1]
[v1]
v2
map[k1:v1 k2:v2]
map[k2:v2]

示例3,GetOrSetFunc*

GetOrSetFunc获取一个缓存值,当缓存不存在时执行指定的f func() (interface{}, error),缓存该f方法的结果值,并返回该结果。

需要注意的是,GetOrSetFunc的缓存方法参数f是在缓存的锁机制外执行,因此在f内部也可以嵌套调用GetOrSetFunc。但如果f的执行比较耗时,高并发的时候容易出现f被多次执行的情况(缓存设置只有第一个执行的f返回结果能够设置成功,其余的被抛弃掉)。而。而GetOrSetFuncLock的缓存方法f是在缓存的锁机制内执行,因此可以保证当缓存项不存在时只会执行一次f,但是缓存写锁的时间随着f方法的执行时间而定。

我们来看一个示例:

Code Block
languagego
package main

import (
	"fmt"
	"github.com/gogf/gf/os/gcache"
	"github.com/gogf/gf/os/gctx"
	"time"
)

func main() {
	var (
		ch    = make(chan struct{}, 0)
		ctx   = gctx.New()
		key   = `key`
		value = `value`
	)
	for i := 0; i < 10; i++ {
		go func(index int) {
			<-ch
			_, _ = gcache.Ctx(ctx).GetOrSetFuncLock(key, func() (interface{}, error) {
				fmt.Println(index, "entered")
				return value, nil
			}, 0)
		}(i)
	}
	close(ch)
	time.Sleep(time.Second)
}

执行后,终端输出(带有随机性,但是只会输出一条信息):

Code Block
languagexml
9 entered

可以看到,多个goroutine同时调用GetOrSetFuncLock方法时,由于该方法有并发安全控制,因此最终只有一个goroutine的数值生成函数执行成功,成功之后其他goroutine拿到数据后则立即返回不再执行对应的数值生成函数。

示例4,LRU缓存淘汰控制

package main

import (
    "github.com/gogf/gf/os/gcache"
    "time"
    "fmt"
)

func main() {
    // 设置LRU淘汰数量
    c := gcache.New(2)

    // 添加10个元素,不过期
    for i := 0; i < 10; i++ {
        c.Set(i, i, 0)
    }
    n, _ := c.Size()
    fmt.Println(n)
    keys, _ := c.Keys()
    fmt.Println(keys)

    // 读取键名1,保证该键名是优先保留
    v, _ := c.Get(1)
    fmt.Println(v)

    // 等待一定时间后(默认1秒检查一次),
    // 元素会被按照从旧到新的顺序进行淘汰
    time.Sleep(2*time.Second)
    n, _ = c.Size()
    fmt.Println(n)
    keys, _ = c.Keys()
    fmt.Println(keys)
}

执行后,输出结果为:

10
[2 4 5 7 8 9 0 1 3 6]
1
2
[1 9]

性能测试

测试环境

CPU: Intel(R) Core(TM) i5-4460  CPU @ 3.20GHz
MEM: 8GB
SYS: Ubuntu 16.04 amd64

测试结果

john@john-B85M:~/Workspace/Go/GOPATH/src/github.com/gogf/gf/os/gcache$ go test *.go -bench=".*" -benchmem
goos: linux
goarch: amd64
Benchmark_CacheSet-4                       2000000        897 ns/op      249 B/op        4 allocs/op
Benchmark_CacheGet-4                       5000000        202 ns/op       49 B/op        1 allocs/op
Benchmark_CacheRemove-4                   50000000       35.7 ns/op        0 B/op        0 allocs/op
Benchmark_CacheLruSet-4                    2000000        880 ns/op      399 B/op        4 allocs/op
Benchmark_CacheLruGet-4                    3000000        212 ns/op       33 B/op        1 allocs/op
Benchmark_CacheLruRemove-4                50000000       35.9 ns/op        0 B/op        0 allocs/op
Benchmark_InterfaceMapWithLockSet-4        3000000        477 ns/op       73 B/op        2 allocs/op
Benchmark_InterfaceMapWithLockGet-4       10000000        149 ns/op        0 B/op        0 allocs/op
Benchmark_InterfaceMapWithLockRemove-4    50000000       39.8 ns/op        0 B/op        0 allocs/op
Benchmark_IntMapWithLockWithLockSet-4      5000000        304 ns/op       53 B/op        0 allocs/op
Benchmark_IntMapWithLockGet-4             20000000        164 ns/op        0 B/op        0 allocs/op
Benchmark_IntMapWithLockRemove-4          50000000       33.1 ns/op        0 B/op        0 allocs/op
PASS
ok   command-line-arguments 47.503s


Panel
titleContent Menu

Table of Contents