1. 支持设定过期时间,精确到秒
2. 支持设定最大内存,当内存超出时作出适当的处理
3. 支持并发安全
4. 按照以下接口要求实现
type Cache interface {
// size 1KB 100KB 1MB 2MB 1GB
SetMaxMemory(size string) bool
// 将value写入缓存
Set(key string, val interface{}, expire time.Duration)
// 根据key值获取value
Get(key string) (interface{},bool)
// 删除key值
Del(key string) bool
// 判断key值是否存在
Exists(key string) bool
// 清空所有key
Flush() bool
// 获取缓存中所有key的数量
Keys() int64
}
5. 使用示例
cache:=NewMemCache()
cache.SetMaxMemory("100MB")
cache.Set("int",1)
cache.Set("bool",false)
cache.Set("data",map[string]interface{}{"a":1})
cache.Get("int")
cache.Del("int")
cache.Flush()
cache.Keys()
log.println的用法
log.Println
函数是Go标准库中用于记录日志的一种方式,通常用于在程序中输出日志信息。它的用法非常简单,可以根据需要输出不同级别的日志信息。下面是log.Println
的几种常见用法:
1. 输出一条普通日志:
log.Println("This is a normal log message.")
这将在标准输出中打印一条普通的日志信息。
2. 输出带有时间戳的日志:
log.SetFlags(log.LstdFlags) // 设置日志格式,包括时间戳 log.Println("This is a log message with a timestamp.")
这将在日志信息前面添加时间戳,以便记录日志的时间。
3. 输出错误日志:
err := someFunction() if err != nil { log.Println("Error:", err) }
这将在发生错误时输出相应的错误日志信息。
4. 自定义日志级别:
const (
LogLevelInfo = iota
LogLevelWarning
LogLevelError
)
func logMessage(level int, message string) {
switch level {
case LogLevelInfo:
log.Println("INFO:", message)
case LogLevelWarning:
log.Println("WARNING:", message)
case LogLevelError:
log.Println("ERROR:", message)
}
}
logMessage(LogLevelWarning, "This is a warning message.")
这个例子演示了如何根据不同的日志级别输出不同类型的日志信息。
5. 输出到文件:
file, err := os.Create("logfile.txt")
if err != nil {
log.Fatal("Cannot create log file:", err)
}
defer file.Close()
log.SetOutput(file)
log.Println("This log message will be written to the file.")
这将日志输出到文件中,而不是默认的标准输出。
这些是log.Println
函数的几种常见用法,可以根据需要选择适合自己场景的用法。
go语言的变量名要求很有意思,需要去复习一下
main.go文件
package main
import (
"test1/cache_server"
"time"
)
func main() {
cache := cache_server.NewMemCache()
cache.SetMaxMemory("300GB")
//
cache.Set("int", 1, time.Second)
cache.Set("bool", false, time.Second)
cache.Set("data", map[string]interface{}{"a": 1}, time.Second)
cache.Set("int", 1)
cache.Set("bool", false)
cache.Set("data", map[string]interface{}{"a": 1})
cache.Get("int")
cache.Del("int")
cache.Flush()
cache.Keys()
//cache.GetValSize(1)
//cache.GetValSize(false)
//cache.GetValSize("张三")
//cache.GetValSize(map[string]string{
// "name": "张三",
// "addr": "张三",
//})
}
util.go文件
package cache
import (
"encoding/json"
"fmt"
"log"
"regexp"
"strconv"
"strings"
)
const (
/*
iota 是 Go 语言中的预定义标识符,用于枚举常量的自增值生成器。在常量声明中,iota 从 0 开始自动递增,每遇到一个 const 关键字都会被重置为 0。
*/
B = 1 << (iota * 10)
KB
MB
GB
TB
PB
)
func ParseSize(size string) (int64, string) {
// 默认大小为100MB
re, _ := regexp.Compile("[0-9]+")
uint := string(re.ReplaceAll([]byte(size), []byte("")))
num, _ := strconv.ParseInt(strings.Replace(size, uint, "", 1), 10, 64)
uint = strings.ToUpper(uint)
var byteNum int64 = 0
switch uint {
case "B":
byteNum = num
case "KB":
byteNum = num * KB
case "MB":
byteNum = num * MB
case "GB":
byteNum = num * GB
case "TB":
byteNum = num * TB
case "PB":
byteNum = num * PB
default:
num = 0
}
if num == 0 {
log.Println("ParseSize 仅支持B,KB,MB,GB,TB,PB")
num = 10
byteNum = num * MB
uint = "MB"
}
sizeStr := strconv.FormatInt(num, 10) + uint
return byteNum, sizeStr
}
// 根据这个值,计算一下它的大小是多少
func GetValSize(val interface{}) int64 {
bytes, _ := json.Marshal(val)
size := int64(len(bytes))
fmt.Println(size)
return size
}
memCache_test.go文件
package cache
import (
"fmt"
"reflect"
"testing"
"time"
)
func TestCacheOP(t *testing.T) {
testData := []struct {
key string
val interface{}
expire time.Duration
}{
{"djksndsdn", 678, time.Second * 10},
{"ddjshf", false, time.Second * 12},
{"ig", true, time.Second * 12},
{"fdggd", map[string]interface{}{"a": 3, "b": false}, time.Second * 11},
{"trtry", "huhu", time.Second * 3},
{"twuuw", "aahha", time.Second * 5},
}
c := NewMemCache()
c.SetMaxMemory("10MB")
for _, item := range testData {
//fmt.Println("ahha")
c.Set(item.key, item.val, item.expire)
//fmt.Println("ahha1")
val, ok := c.Get(item.key)
//fmt.Println("ahha2")
if !ok {
t.Error("缓存取值失败")
}
if !reflect.DeepEqual(val, item.val) {
t.Errorf("缓存取值数据与预期的不一样,key: %s, 期望: %v, 实际: %v", item.key, item.val, val)
}
}
if int64(len(testData)) != c.Keys() {
t.Errorf("缓存数量不一样,期望: %d, 实际: %d", len(testData), c.Keys())
}
fmt.Println("ahah")
c.Del(testData[0].key)
c.Del(testData[1].key)
if int64(len(testData))-2 != c.Keys() {
t.Errorf("缓存数量不一样,期望: %d, 实际: %d", len(testData)-2, c.Keys())
}
fmt.Println("finish")
time.Sleep(time.Second * 16)
if c.Keys() != 0 {
t.Error("过期缓存清空失败")
}
}
memCache.go文件
package cache
import (
"log"
"sync"
"time"
)
type memCache struct {
maxMemorySize int64 // 最大的内存空间是多少
maxMemorySizeStr string // 这个内存空间用字符串表示是多少
currMemorySize int64 // 当前使用了多少内存
values map[string]*memCacheValue
locker sync.RWMutex
clearExpireItemTimeInterval time.Duration // 相隔多长时间删除一些过期的内容
}
type memCacheValue struct { // 内存空间里面的每一步的结构是什么样的
val interface{} // 它的值是多少
expireTime time.Time // 它的过期时间是多少
expire time.Duration // 还有多少时间过期
/*
time.Duration 是 Go 语言中用于表示时间间隔(持续时间)的类型。它是一个有符号整数类型,单位为纳秒(nanoseconds)。
*/
size int64 // 它占这一个内存空间的大小是多少
}
// 首先应该先给创建这么一个实例一个方法
func NewMemCache() *memCache {
mc := &memCache{
values: make(map[string]*memCacheValue),
clearExpireItemTimeInterval: time.Second,
}
go mc.clearExpireItemTime()
return mc
}
// 怎么清空呢
func (mc *memCache) clearExpireItemTime() {
timeTicker := time.NewTicker(mc.clearExpireItemTimeInterval)
defer timeTicker.Stop()
for {
select {
case <-timeTicker.C:
mc.locker.Lock()
for key, item := range mc.values {
if item.expire != 0 && time.Now().After(item.expireTime) {
mc.del(key)
}
}
mc.locker.Unlock()
}
}
}
// 根据key值找到val值 然后删除它 但是需要提前判断是否存在这个键值对
func (mc *memCache) del(key string) {
if val, exists := mc.values[key]; exists {
mc.currMemorySize -= val.size
delete(mc.values, key)
}
}
// 设置最大的内存
func (mc *memCache) SetMaxMemory(size string) bool {
mc.maxMemorySize, mc.maxMemorySizeStr = ParseSize(size)
return true
}
// 将value写入缓存
func (mc *memCache) Set(key string, val interface{}, expire time.Duration) bool {
mc.locker.Lock()
defer mc.locker.Unlock()
v := &memCacheValue{
val: val,
expireTime: time.Now().Add(expire),
expire: expire,
size: GetValSize(val),
}
mc.del(key)
mc.add(key, v)
if mc.currMemorySize > mc.maxMemorySize {
mc.del(key)
log.Printf("max memory size exceeded: %d", mc.maxMemorySize)
return false
}
return true
}
func (mc *memCache) add(key string, val *memCacheValue) {
mc.values[key] = val
mc.currMemorySize += val.size
}
// 根据key值获取value
func (mc *memCache) Get(key string) (interface{}, bool) {
mc.locker.RLock()
defer mc.locker.RUnlock()
mcv, ok := mc.get(key)
if ok {
if mcv.expire != 0 && time.Now().After(mcv.expireTime) {
mc.del(key)
return nil, false
}
return mcv.val, true
}
return nil, false
}
func (mc *memCache) get(key string) (*memCacheValue, bool) {
val, ok := mc.values[key]
return val, ok
}
// 删除key值
func (mc *memCache) Del(key string) bool {
mc.locker.Lock()
defer mc.locker.Unlock()
mc.del(key)
return true
}
// 判断key值是否存在
func (mc *memCache) Exists(key string) bool {
mc.locker.RLock()
defer mc.locker.RUnlock()
_, ok := mc.values[key]
return ok
}
// 清空所有key
func (mc *memCache) Flush() bool {
mc.locker.Lock()
defer mc.locker.Unlock()
mc.values = make(map[string]*memCacheValue)
mc.currMemorySize = 0
return true
}
// 获取缓存中所有key的数量
func (mc *memCache) Keys() int64 {
mc.locker.RLock()
defer mc.locker.RUnlock()
return int64(len(mc.values))
}
Cache.go文件
package cache
import "time"
type Cache interface {
// size 1KB 100KB 1MB 2MB 1GB
SetMaxMemory(size string) bool
// 将value写入缓存
Set(key string, val interface{}, expire time.Duration) bool
// 根据key值获取value
Get(key string) (interface{}, bool)
// 删除key值
Del(key string) bool
// 判断key值是否存在
Exists(key string) bool
// 清空所有key
Flush() bool
// 获取缓存中所有key的数量
Keys() int64
}
cacheServer.go
package cache_server
import (
"test1/cache"
"time"
)
type cacheServer struct {
memCache cache.Cache
}
func NewMemCache() *cacheServer {
return &cacheServer{
memCache: cache.InitCache(),
}
}
func (cs *cacheServer) SetMaxMemory(size string) bool {
return cs.memCache.SetMaxMemory(size)
}
// 将value写入缓存
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)
}
// 根据key值获取value
func (cs *cacheServer) Get(key string) (interface{}, bool) {
return cs.memCache.Get(key)
}
// 删除key值
func (cs *cacheServer) Del(key string) bool {
return cs.memCache.Del(key)
}
// 判断key值是否存在
func (cs *cacheServer) Exists(key string) bool {
return cs.memCache.Exists(key)
}
// 清空所有key
func (cs *cacheServer) Flush() bool {
return cs.memCache.Flush()
}
// 获取缓存中所有key的数量
func (cs *cacheServer) Keys() int64 {
return cs.memCache.Keys()
}