首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >每日一库之 go-cache 单机缓存

每日一库之 go-cache 单机缓存

原创
作者头像
浩瀚星河
修改2025-07-04 01:05:09
修改2025-07-04 01:05:09
1940
举报
文章被收录于专栏:golanggolang

go-cache 是一个 golang 的缓存库, 用于缓存 k, v 对, 缓存时间过期后存储的值会失效, 底层是一个 map, 过期后内部 Item 是不会自动清除, 需要手动调用DeleteExpired方法清除过期项

安装

代码语言:bash
复制
go get github.com/patrickmn/go-cache

使用方法

代码语言:go
复制
// 创建Cache对象, 第一个参数为缓存时间, 第二个参数为清理缓存项的时间间隔
// 底层是一个map, 过期后内部Item是不会自动清除
c := cache.New(30*time.Second, 1*time.Minute)

// 设置k, v对
c.Set("name", "codepzj", cache.DefaultExpiration)

// 获得k, v对, found 为false则代表过期
val, found := c.Get("name")

其他参数

方法名

类型

说明

示例

GetWithExpiration(key)

方法

获取值和过期时间

val, exp, found := c.GetWithExpiration("k")

Add(key, value, duration)

方法

添加新项,若存在返回错误

err := c.Add("k", "v", 1*time.Hour)

Replace(key, value, duration)

方法

替换已存在项,否则报错

err := c.Replace("k", "new", 2*time.Minute)

Delete(key)

方法

删除指定 key

c.Delete("k")

DeleteExpired()

方法

删除所有过期项

c.DeleteExpired()

Flush()

方法

清空所有缓存项

c.Flush()

Items()

方法

返回所有缓存项(包含过期未清理的)

items := c.Items()

示例代码

这里写一个简单的示例代码, 使用 gin 框架

代码语言:go
复制
package main

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/patrickmn/go-cache"
)

func main() {
	r := gin.Default()
	c := cache.New(30*time.Second, 1*time.Minute)
	r.GET("/", func(ctx *gin.Context) {
		c.Set("name", "codepzj", cache.DefaultExpiration)
		ctx.String(200, "set name successfully")
	})
	r.GET("/cache", func(ctx *gin.Context) {
		fmt.Println("cache items", c.Items())
		val, exp, found := c.GetWithExpiration("name")
		if found {
			ctx.String(200, "get cache successfully, value %s, expired at %s", val, exp.Format("2006-01-02 15:04:05"))
			return
		}
		ctx.String(200, "get cache failed, expired")
	})
	r.GET("/delete", func(ctx *gin.Context) {
		c.Delete("name")
		ctx.String(200, "delete cache successfully")
	})
	r.Run(":8080")
}

底层剖析

数据结构

代码语言:go
复制
type cache struct {
	defaultExpiration time.Duration
	items             map[string]Item
	mu                sync.RWMutex
	onEvicted         func(string, interface{})
	janitor           *janitor
}

type Item struct {
	Object     interface{}
	Expiration int64
}
  • defaultExpiration是默认过期时间, 如果设置为 0, 则表示永不过期
  • items是缓存项的 map, 键是 string, 值是 Item
  • mu是互斥锁, 用于保护items的并发访问
  • onEvicted是删除缓存项时的回调函数, 当缓存项过期时, 会调用该函数
  • janitor是清理缓存项的定时器, 会定时清理过期缓存项

Get 和 Set 详解

Get 方法
代码语言:go
复制
func (c *cache) Get(k string) (interface{}, bool) {
	c.mu.RLock()
	// "Inlining" of get and Expired
	item, found := c.items[k]
	if !found {
		c.mu.RUnlock()
		return nil, false
	}
	if item.Expiration > 0 {
		if time.Now().UnixNano() > item.Expiration {
			c.mu.RUnlock()
			return nil, false
		}
	}
	c.mu.RUnlock()
	return item.Object, true
}

在 Get 方法中, 首先会加锁, 可以防止在读取的时候, 其他 goroutine 修改 items, 并且能够并发访问

然后会判断缓存项是否过期, 如果过期, 则返回 false, 否则返回 true

Set 方法
代码语言:go
复制
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()
}

设置写锁,防止多个 goroutine 同时修改一个 item, 然后设置过期时间

这就是 go-cache 库, 主要用于单机缓存,底层是一个 map, 使用RWMutex锁控制读写和time.Now().Add(d).UnixNano()设置过期时间, 基于本地内存 , 如果需要分布式缓存, 可以考虑使用 redis 等其他缓存库

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装
  • 使用方法
  • 其他参数
  • 示例代码
  • 底层剖析
    • 数据结构
    • Get 和 Set 详解
      • Get 方法
      • Set 方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档