go实现一个内存缓存系统的示例代码

 更新时间:2024年10月18日 10:43:55   作者:Monkey@  
本文主要介绍了go实现一个内存缓存系统的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

面试内容:

  • 支持设定过期时间,精度到秒
  • 支持设定最大内存,当内存超出时做出合适的处理
  • 支持并发安全
  • 要求按照以下接口实现
SetMemory(size string) bool
	Set(key string, val interface{}, expire time.Duration) bool
	Get(key string) (interface{}, bool)
	Del(key string) bool
	Exists(key string) bool
	Flush() bool
	Keys() int64

下面为具体实现代码:

接口

package cache
import "time"
type Cache interface {
	SetMemory(size string) bool
	Set(key string, val interface{}, expire time.Duration) bool
	Get(key string) (interface{}, bool)
	Del(key string) bool
	Exists(key string) bool
	Flush() bool
	Keys() int64
}

实现类

package cache

import (
	"fmt"
	"sync"
	"time"
)

type MemCache struct {
	//最大内存
	maxMemorySize int64
	// 当前已使用的内存
	currMemorySize int64
	// 最大内存字符串表示
	maxMemorySizeStr string
	// 缓存键值对
	values map[string]*memCacheValue
	// 读写锁
	lock sync.RWMutex
	//设置清除过期缓存的时间间隔
	clearExpireTime time.Duration
}

type memCacheValue struct {
	//value 值
	val interface{}
	// 过期时间
	expireTime time.Time
	//有效时间
	expire time.Duration
	//value 大小
	size int64
}

func NewMemCache() Cache {
	mc := &MemCache{
		clearExpireTime: time.Second * 10,
		values:          make(map[string]*memCacheValue),
	}
	go mc.clearExpireItm()
	return mc
}

// SetMemory size 1KB 100KB 1M 2M 1GB
func (mc *MemCache) SetMemory(size string) bool {
	mc.maxMemorySize, mc.maxMemorySizeStr = ParseSize(size)
	return true
}

// Set 设置缓存
func (mc *MemCache) Set(key string, val interface{}, expire time.Duration) bool {
	mc.lock.Lock()
	defer mc.lock.Unlock()
	v := &memCacheValue{val: val, expireTime: time.Now().Add(expire),
		expire: expire,
		size:   GetValSize(val)}
	//mc.values[key] = v
	mc.del(key)
	mc.add(key, v)
	if mc.currMemorySize > mc.maxMemorySize {
		mc.del(key)
		panic(fmt.Sprintf("max memory size %d", mc.maxMemorySize))
	}
	return true
}

func (mc *MemCache) get(key string) (*memCacheValue, bool) {
	val, ok := mc.values[key]
	return val, ok
}

func (mc *MemCache) del(key string) {
	tmp, ok := mc.get(key)
	if ok && tmp != nil {
		mc.currMemorySize -= tmp.size
		delete(mc.values, key)
	}
}

func (mc *MemCache) add(key string, val *memCacheValue) {
	mc.values[key] = val
	mc.currMemorySize += val.size
}

// Get 获取缓存值
func (mc *MemCache) Get(key string) (interface{}, bool) {
	mc.lock.RLock()
	defer mc.lock.RUnlock()
	mcv, ok := mc.get(key)
	if ok {
		if mcv.expire != 0 && mcv.expireTime.Before(time.Now()) {
			mc.del(key)
			return nil, false
		}
		return mcv.val, ok
	}
	return nil, false
}

// Del 删除缓存值
func (mc *MemCache) Del(key string) bool {
	mc.lock.Lock()
	defer mc.lock.Unlock()
	mc.del(key)
	return true
}

func (mc *MemCache) Exists(key string) bool {
	mc.lock.RLock()
	defer mc.lock.RUnlock()
	_, ok := mc.get(key)
	return ok
}

func (mc *MemCache) Flush() bool {
	mc.lock.Lock()
	defer mc.lock.Unlock()
	mc.values = make(map[string]*memCacheValue, 0)
	mc.currMemorySize = 0
	return true
}

func (mc *MemCache) Keys() int64 {
	mc.lock.RLock()
	defer mc.lock.RUnlock()
	return int64(len(mc.values))
}

func (mc *MemCache) clearExpireItm() {
	ticker := time.NewTicker(mc.clearExpireTime)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			for key, v := range mc.values {
				if v.expire != 0 && time.Now().After(v.expireTime) {
					mc.lock.Lock()
					mc.del(key)
					mc.lock.Unlock()
				}
			}
		}
	}
}

//
//var Cache = NewMemCache()
//
//func Set(key string, val interface{}) bool {
//
//	return false
//}

工具类

package cache

import (
	"log"
	"regexp"
	"strconv"
	"strings"
)

const (
	B = 1 << (iota * 10)
	KB
	MB
	GB
	TB
	PB
)

func ParseSize(size string) (int64, string) {

	//默认大小为 100M
	re, _ := regexp.Compile("[0-9]+")
	unit := string(re.ReplaceAll([]byte(size), []byte("")))
	num, _ := strconv.ParseInt(strings.Replace(size, unit, "", 1), 10, 64)
	unit = strings.ToUpper(unit)
	var byteNum int64 = 0
	switch unit {
	case "B":
		byteNum = num
		break
	case "KB":
		byteNum = num * KB
		break
	case "MB":
		byteNum = num * MB
		break
	case "GB":
		byteNum = num * GB
		break
	case "TB":
		byteNum = num * TB
		break
	case "PB":
		byteNum = num * PB
		break
	default:
		num = 0
		byteNum = 0

	}
	if num == 0 {
		log.Println("ParseSize 仅支持B,KB,MB,GB,TB,PB")
		num = 100 * MB
		byteNum = num
		unit = "MB"
	}
	sizeStr := strconv.FormatInt(num, 10) + unit
	return byteNum, sizeStr

}

func GetValSize(val interface{}) int64 {
	return 0
}

代理类

package server

import (
	"go_lang_pro/cache"
	"time"
)

type cacheServer struct {
	memCache cache.Cache
}

func NewMemoryCache() *cacheServer {
	return &cacheServer{
		memCache: cache.NewMemCache(),
	}
}

func (cs *cacheServer) SetMemory(size string) bool {
	return cs.memCache.SetMemory(size)
}

func (cs *cacheServer) Set(key string, val interface{}, expire ...time.Duration) bool {
	expirets := time.Second * 0
	if len(expire) > 0 {
		expirets = expire[0]
	}
	return cs.memCache.Set(key, val, expirets)
}

func (cs *cacheServer) Get(key string) (interface{}, bool) {
	return cs.memCache.Get(key)
}
func (cs *cacheServer) Del(key string) bool {
	return cs.memCache.Del(key)
}

func (cs *cacheServer) Exists(key string) bool {
	return cs.memCache.Exists(key)
}

func (cs *cacheServer) Flush() bool {
	return cs.memCache.Flush()
}

func (cs *cacheServer) Keys() int64 {
	return cs.memCache.Keys()
}

main 方法

package main

import (
	"go_lang_pro/cache"
	"time"
)

func main() {

	cache := cache.NewMemCache()
	cache.SetMemory("100MB")
	cache.Set("int", 1, time.Second)
	cache.Set("bool", false, time.Second)
	cache.Set("data", map[string]interface{}{"a": 1}, time.Second)
	cache.Get("int")
	cache.Del("int")
	cache.Flush()
	cache.Keys()

}

到此这篇关于go实现一个内存缓存系统的示例代码的文章就介绍到这了,更多相关go 内存缓存系统内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • go语言channel实现多核并行化运行的方法

    go语言channel实现多核并行化运行的方法

    这篇文章主要介绍了go语言channel实现多核并行化运行的方法,实例分析了channel实现多核并行化运行的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • Golang编写自定义IP限流中间件的方法详解

    Golang编写自定义IP限流中间件的方法详解

    这篇文章给大家详细的介绍了Golang编写自定义IP限流中间件的方法,文章通过代码实例介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2023-09-09
  • Golang channel底层实现过程解析(深度好文)

    Golang channel底层实现过程解析(深度好文)

    Go语言为了方便使用者,提供了简单、安全的协程数据同步和通信机制,这篇文章主要介绍了Golang channel底层是如何实现的,需要的朋友可以参考下
    2024-07-07
  • Go语言基础函数基本用法及示例详解

    Go语言基础函数基本用法及示例详解

    这篇文章主要为大家介绍了Go语言基础函数基本用法及示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2021-11-11
  • 详解Golang如何优雅的终止一个服务

    详解Golang如何优雅的终止一个服务

    后端服务通常会需要创建子协程来进行相应的作业,但进程接受到终止信号或正常结束时,并没有判断或等待子协程执行结束,下面这篇文章主要给大家介绍了关于Golang如何优雅的终止一个服务的相关资料,需要的朋友可以参考下
    2022-03-03
  • gorm整合进go-zero的实现方法

    gorm整合进go-zero的实现方法

    go-zero提供的代码生成器里面,没有提供orm框架操作,但是提供了遍历的缓存操作,所以可以利用gorm当作一个sql语句的生成器,把生成后的sql语句放到go-zero生成的模板中去执行,对gorm整合进go-zero的实现方法感兴趣的朋友一起看看吧
    2022-03-03
  • 浅谈Go语言多态的实现与interface使用

    浅谈Go语言多态的实现与interface使用

    如果大家系统的学过C++、Java等语言以及面向对象的话,相信应该对多态不会陌生。多态是面向对象范畴当中经常使用并且非常好用的一个功能,它主要是用在强类型语言当中,像是Python这样的弱类型语言,变量的类型可以随意变化,也没有任何限制,其实区别不是很大
    2021-06-06
  • go语言中结构体tag使用小结

    go语言中结构体tag使用小结

    Go语言是一种静态类型、编译型的编程语言,其中结构体是一种非常重要的数据类型,本文就来介绍一下go语言中结构体tag使用,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • go语言string转结构体的实现

    go语言string转结构体的实现

    本文主要介绍了go语言string转结构体的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • 解决go语言ssh客户端密码过期问题

    解决go语言ssh客户端密码过期问题

    这篇文章主要介绍了go语言ssh客户端解决密码过期问题,本文给大家分享了解决的方法和原理,非常不错,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04

最新评论