golang cache带索引超时缓存库实战示例

目录
  • 正文
  • 定义泛型函数
    • Filter 函数
    • Map 函数
    • First 函数
  • 带超时的cache
    • cache 结构
  • 集合操作
    • set 结构
  • 带索引的cache
    • index 结构

正文

cache 是一个带索引带超时的缓存库

目的在于优化代码结构,提供了若干实践。 https://github.com/weapons97/cache

example

定义泛型函数

1.18 已经发布一段实践了。通过泛型函数。我们可以减少循环的使用,优化代码结构。下面分享几个泛型函数和代码上的实践。

Filter 函数

// Filter filter one slice
func Filter[T any](objs []T, filter func(obj T) bool) []T {
    res := make([]T, 0, len(objs))
    for i := range objs {
        ok := filter(objs[i])
        if ok {
            res = append(res, objs[i])
        }
    }
    return res
}
// 测试[]int
func TestFilter(t *testing.T) {
    ans := []int{2, 4, 6}
    a := []int{1, 2, 3, 4, 5, 6}
    b := Filter(a, func(i int) bool {
        return i%2 == 0
    })
    require.Equal(t, ans, b)
    spew.Dump(b)
}
// 结果
=== RUN   TestFilter
([]int) (len=3 cap=6) {
 (int) 2,
 (int) 4,
 (int) 6
}
--- PASS: TestFilter (0.00s)
PASS
// NoSpace is filter func for strings
func NoSpace(s string) bool {
    return strings.TrimSpace(s) != ""
}
// 测试[]sting
func TestFilterNoSpace(t *testing.T) {
    ans1 := []string{"1", "2", "3"}
    a := []string{"", "1", "", "2", "", "3", ""}
    b := Filter(a, NoSpace)
    require.Equal(t, ans1, b)
    spew.Dump(b)
}
// 结果
=== RUN   TestFilterNoSpace
([]string) (len=3 cap=7) {
 (string) (len=1) "1",
 (string) (len=1) "2",
 (string) (len=1) "3"
}
--- PASS: TestFilterNoSpace (0.00s)
PASS

Map 函数

// Map one slice
func Map[T any, K any](objs []T, mapper func(obj T) ([]K, bool)) []K {
    res := make([]K, 0, len(objs))
    for i := range objs {
        others, ok := mapper(objs[i])
        if ok {
            res = append(res, others...)
        }
    }
    return res
}
// 测试 []int -> []string
func TestMap(t *testing.T) {
    ans := []string{"2", "4", "6", "end"}
    a := []int{1, 2, 3, 4, 5, 6}
    b := Map(a, func(i int) ([]string, bool) {
        if i == 6 {
            return []string{fmt.Sprintf(`%v`, i), `end`}, true
        }
        if i%2 == 0 {
            return []string{fmt.Sprintf(`%v`, i)}, true
        } else {
            return nil, false
        }
    })
    require.Equal(t, ans, b)
    spew.Dump(b)
}
// 结果
=== RUN   TestMap
([]string) (len=4 cap=6) {
 (string) (len=1) "2",
 (string) (len=1) "4",
 (string) (len=1) "6",
 (string) (len=3) "end"
}
--- PASS: TestMap (0.00s)
PASS

First 函数

// First make return first for slice
func First[T any](objs []T) (T, bool) {
    if len(objs) > 0 {
        return objs[0], true
    }
    return *new(T), false
}
func TestFirstInt(t *testing.T) {
    ans1, ans2 := 1, 0
    a := []int{1, 2, 3, 4, 5, 6}
    b, ok := First(a)
    require.True(t, ok)
    require.Equal(t, ans1, b)
    spew.Dump(b)
    c := []int{}
    d, ok := First(c)
    require.False(t, ok)
    require.Equal(t, ans2, d)
    spew.Dump(d)
}
// result
=== RUN   TestFirstInt
(int) 1
(int) 0
--- PASS: TestFirstInt (0.00s)
PASS
func TestFirstString(t *testing.T) {
    ans1, ans2 := "1", ""
    a := []string{"1", "2", "3", "4", "5", "6"}
    b, ok := First(a)
    require.True(t, ok)
    require.Equal(t, ans1, b)
    spew.Dump(b)
    c := []string{}
    d, ok := First(c)
    require.False(t, ok)
    require.Equal(t, ans2, d)
    spew.Dump(d)
}
// result
=== RUN   TestFirstString
(string) (len=1) "1"
(string) ""
--- PASS: TestFirstString (0.00s)
PASS

带超时的cache

  • 某些情况下,我们删除过期的cache, 通过利用带超时的cache,简化代码

cache 结构

// 用辅助map删除
if apiRet.TotalCount > 0 {
var hc sync.Map
for _, h := range apiRet.Hcis {
hc.Store(h.HostID, h)
hostCpu.Store(h.HostID, h)
}
hostCpu.Range(func(key, _ interface{}) bool {
_, ok := hc.Load(key)
if !ok {
 hostCpu.Delete(key)
}
return true
})
}
// 直接设置,过期的key 会删除
for _, h := range apiRet.Hcis {
  hostCpu.Set(h.HostID, h)
}
func TestNewCache(t *testing.T) {
  c := NewCache(WithTTL[string, int](time.Second))
  b := 1
  c.Set(`a`, b)
  d, ok := c.Get(`a`)
  require.True(t, ok)
  require.Equal(t, b, d)
  time.Sleep(time.Second)
  d, ok = c.Get(`a`)
  require.False(t, ok)
  // 超时返回0值
  require.Equal(t, d, 0)
}

集合操作

通过 set 做集合,可以给集合去重。可以给结合相并,想交,等操作。

set 结构

func TestSetUnion(t *testing.T) {
    s := NewSet[string]()
    s.Add(`a`)
    s.Add(`b`)
    s2 := NewSet[string]()
    s2.Add(`b`)
    s2.Add(`d`)
    s3 := s.Union(s2)
    wantS3 := []string{`a`, `b`, `d`}
    ans := s3.List()
    sort.Strings(ans)
    require.Equal(t, wantS3, ans)
    spew.Dump(s.List(), s2.List(), s3.List())
}
func TestSetJoin(t *testing.T) {
    s := NewSet[string]()
    s.Add(`a`)
    s.Add(`b`)
    s2 := NewSet[string]()
    s2.Add(`b`)
    s2.Add(`d`)
    s3 := s.Join(s2)
    wantS3 := []string{`b`}
    ans := s3.List()
    sort.Strings(ans)
    require.Equal(t, wantS3, ans)
    spew.Dump(s.List(), s2.List(), s3.List())
}
func TestSetJoinLeft(t *testing.T) {
    s := NewSet[string]()
    s.Add(`a`)
    s.Add(`b`)
    s2 := NewSet[string]()
    s2.Add(`b`)
    s2.Add(`d`)
    s3 := s.JoinLeft(s2)
    wantS3 := []string{`a`, `b`}
    ans := s3.List()
    sort.Strings(ans)
    require.Equal(t, wantS3, ans)
    spew.Dump(s.List(), s2.List(), s3.List())
}
func TestSetJoinRight(t *testing.T) {
    s := NewSet[string]()
    s.Add(`a`)
    s.Add(`b`)
    s2 := NewSet[string]()
    s2.Add(`b`)
    s2.Add(`d`)
    s3 := s.JoinRight(s2)
    wantS3 := []string{`b`, `d`}
    ans := s3.List()
    sort.Strings(ans)
    require.Equal(t, wantS3, ans)
    spew.Dump(s.List(), s2.List(), s3.List())
}
func TestSetSub(t *testing.T) {
    s := NewSet[string]()
    s.Add(`a`)
    s.Add(`b`)
    s2 := NewSet[string]()
    s2.Add(`b`)
    s2.Add(`d`)
    s3 := s.Sub(s2)
    wantS3 := []string{`a`}
    ans := s3.List()
    sort.Strings(ans)
    require.Equal(t, wantS3, ans)
    spew.Dump(s.List(), s2.List(), s3.List())
}

通过set 去重

// ShowImageInManifest 抓取 manifest 中imgs
func ShowImageInManifest(manifest string) (imgs []string) {
    rx := regImages.FindAllStringSubmatch(manifest, -1)
    set := cache.NewSet[string]()
    for i := range rx {
        for j := range rx[i] {
            if strings.HasPrefix(rx[i][j], `image:`) {
                continue
            }
            tx0 := strings.TrimSpace(rx[i][j])
            tx1 := strings.Trim(tx0, `'`)
            tx2 := strings.Trim(tx1, `"`)
            set.Add(tx2)
        }
    }
    imgs = set.List()
    return imgs
}

带索引的cache

某些情况下,我们可能根据cache 的某个元素对cache进行遍历,这时候如果给cache 加上索引结构,可以对遍历加速。

index 结构

type Person struct {
    id       string
    lastName string
    fullName string
    country  string
}
const (
    IndexByLastName = `IndexByLastName`
    IndexByCountry  = `IndexByCountry`
)
func (p *Person) Indexs() map[string]IndexFunc {
    return map[string]IndexFunc{
        IndexByLastName: func(indexed Indexed) (key []string) {
            ci := indexed.(*Person)
            return []string{ci.lastName}
        },
        IndexByCountry: func(indexed Indexed) (key []string) {
            ci := indexed.(*Person)
            return []string{ci.country}
        },
    }
}
func (p *Person) ID() (mainKey string) {
    return p.id
}
func (p *Person) Set(v interface{}) (Indexed, bool) {
    rx, ok := v.(*Person)
    if !ok {
        return nil, false
    }
    return rx, true
}
func (p *Person) Get(v Indexed) (interface{}, bool) {
    rx, ok := v.(*Person)
    if !ok {
        return nil, false
    }
    return rx, true
}
// 测试数据
var (
    p1 = &Person{
        id:       `1`,
        lastName: "魏",
        fullName: "魏鹏",
        country:  `China`,
    }
    p2 = &Person{
        id:       `2`,
        lastName: "魏",
        fullName: "魏无忌",
        country:  `America`,
    }
    p3 = &Person{
        id:       `3`,
        lastName: "李",
        fullName: "李云",
        country:  `China`,
    }
    p4 = &Person{
        id:       `4`,
        lastName: "黄",
        fullName: "黄帅来",
        country:  `China`,
    }
    p5 = &Person{
        id:       `5`,
        lastName: "Cook",
        fullName: "TimCook",
        country:  `America`,
    }
    p6 = &Person{
        id:       `6`,
        lastName: "Jobs",
        fullName: "SteveJobs",
        country:  `America`,
    }
    p7 = &Person{
        id:       `7`,
        lastName: "Musk",
        fullName: "Elon Musk",
        country:  `America`,
    }
)
func TestIndexByCountry(t *testing.T) {
    index := NewIndexer(&Person{})
    // set
    index.Set(p1)
    index.Set(p2)
    index.Set(p3)
    index.Set(p4)
    index.Set(p5)
    index.Set(p6)
    index.Set(p7)
    // search
    rs := index.Search(IndexByCountry, `China`)
    require.False(t, rs.Failed())
    rx := rs.InvokeAll()
    require.Len(t, rx, 3)
    spew.Dump(rx)
    one := rs.InvokeOne().(*Person)
    require.Equal(t, one.country, `China`)
    spew.Dump(one)
}
// result
=== RUN   TestIndexByCountry
([]interface {}) (len=3 cap=3) {
 (*cache.Person)(0x14139c0)({
  id: (string) (len=1) "3",
  lastName: (string) (len=3) "李",
  fullName: (string) (len=6) "李云",
  country: (string) (len=5) "China"
 }),
 (*cache.Person)(0x1413a00)({
  id: (string) (len=1) "4",
  lastName: (string) (len=3) "黄",
  fullName: (string) (len=9) "黄帅来",
  country: (string) (len=5) "China"
 }),
 (*cache.Person)(0x1413940)({
  id: (string) (len=1) "1",
  lastName: (string) (len=3) "魏",
  fullName: (string) (len=6) "魏鹏",
  country: (string) (len=5) "China"
 })
}
(*cache.Person)(0x14139c0)({
 id: (string) (len=1) "3",
 lastName: (string) (len=3) "李",
 fullName: (string) (len=6) "李云",
 country: (string) (len=5) "China"
})
--- PASS: TestIndexByCountry (0.00s)
PASS

以上就是golang cache带索引超时缓存库实战示例的详细内容,更多关于golang cache索引超时缓存库的资料请关注我们其它相关文章!

(0)

相关推荐

  • 在 Golang 中实现 Cache::remember 方法详解

    项目需要把部分代码移植到 Golang , 之前用 Laravel 封装的写起来很舒服,在 Golang 里只能自动动手实现. 一开始想的是使用 interface 实现,但是遇到了一个坑, Golang 里的组合是一个虚假的继承 package main import "fmt" type Person interface { Say() Name() } type Parent struct { } func (s *Parent) Say() { fmt.Println(&quo

  • django中使用memcached示例详解

    目录 什么是memcached: 安装和启动memcached: windows linux(ubuntu) 启动memcached: telnet操作memcached: 添加数据: 获取数据: 删除数据: 通过python操作memcached: memcached的安全性: 在Django中使用memcached: 什么是memcached: memcached之前是danga的一个项目,最早是为LiveJournal服务的,当初设计师为了加速LiveJournal访问速度而开发的,后来被

  • golang中cache组件的使用及groupcache源码解析

    groupcache 简介 在软件系统中使用缓存,可以降低系统响应时间,提高用户体验,降低某些系统模块的压力. groupcache是一款开源的缓存组件.与memcache与redis不同的时,groupcache不需要单独的部署,可以作为你程序的一个库来使用. 这样方便我们开发的程序部署. 本篇主要解析groupcache源码中的关键部分, lru的定义以及如何做到同一个key只加载一次. 缓存填充以及加载抑制的实现 上篇有提到load函数的实现, 缓存填充的逻辑也体现在这里. groupca

  • 如何利用Go语言实现LRU Cache

    目录 1基本概念 2代码实现 3测试使用 1 基本概念 LRU是一个老生常谈的问题,即最近最少使用,LRU是Least Recently Used的缩写,是一种操作系统中常用的页面置换算法,选择最近最久未使用的页面予以淘汰.该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰. 实现LRU基本的数据结构:Map+LinkedList 一般规则: 添加数据时,将新增数据节点放在头指针,尾结

  • GoFrame gcache 缓存控制 淘汰策略

    目录 打印结果 缓存控制 打印结果 场景分析 代码示例 打印结果 GetOrSetFunc的使用 基本概念 gcache模块默认提供的是一个高速的内存缓存,操作效率非常高效,CPU性能损耗在ns纳秒级别.使用简单易上手,非常适合单机应用使用. 基本使用 我们可以通过gcache.New()创建一个缓存对象 也可以直接使用gcache包方法,使用方式都是一样的. 下面代码段介绍了gcache的基本使用: package main import ( "fmt" "github.c

  • Mango Cache缓存管理库TinyLFU源码解析

    目录 介绍 整体架构 初始化流程 读流程 写流程 事件处理机制 主流程 write 清理工作 缓存管理 什么是LRU? 什么是SLRU? 什么是TinyLFU? mango Cache中的TinyLFU counter counter的初始化 counter的使用 lruCache slruCache filter TinyLFU的初始化 TinyLFU写入 TinyLFU访问 增加entry的访问次数 估计entry访问次数 总结 介绍 据官方所述,mango Cache是对Guava Cac

  • golang cache带索引超时缓存库实战示例

    目录 正文 定义泛型函数 Filter 函数 Map 函数 First 函数 带超时的cache cache 结构 集合操作 set 结构 带索引的cache index 结构 正文 cache 是一个带索引带超时的缓存库 目的在于优化代码结构,提供了若干实践. https://github.com/weapons97/cache example 定义泛型函数 1.18 已经发布一段实践了.通过泛型函数.我们可以减少循环的使用,优化代码结构.下面分享几个泛型函数和代码上的实践. Filter 函

  • Spring Cache手动清理Redis缓存

    这篇文章主要介绍了Spring Cache手动清理Redis缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 注册cacheRedisTemplate 将 cache 的 RedisTemplate 注册为Bean @Bean(name = "cacheRedisTemplate") public RedisTemplate cacheRedisTemplate(@Qualifier("jedisConnectionFac

  • node强缓存和协商缓存实战示例

    目录 前言 什么是浏览器缓存 优点 强缓存 Expires Cache-Control 协商缓存 ETag.If-None-Match node实践 koa启动服务 创建项目 koa代码 原生koa实现简易静态资源服务 强缓存验证 设置Expire 协商缓存验证 小结 总结 前言 浏览器缓存是性能优化非常重要的一个方案,合理地使用缓存可以提高用户体验,还能节省服务器的开销.掌握好缓存的原理和并合理地使用无论对前端还是运维都是相当重要的. 什么是浏览器缓存 浏览器缓存(http 缓存) 是指浏览器

  • 深入理解go缓存库freecache的使用

    目录 1 初始化 2 读写流程 3 总结 go开发缓存场景一般使用map或者缓存框架,为了线程安全会使用sync.Map或线程安全的缓存框架. 缓存场景中如果数据量大于百万级别,需要特别考虑数据类型对于gc的影响(注意string类型底层是指针+Len+Cap,因此也算是指针类型),如果缓存key和value都是非指针类型的话就无需多虑了.但实际应用场景中,key和value是(包含)指针类型数据是很常见的,因此使用缓存框架需要特别注意其对gc影响,从是否对GC影响角度来看缓存框架大致分为2类:

  • Redis+Caffeine实现分布式二级缓存组件实战教程

    目录 前言 所谓二级缓存 分布式二级缓存的优势 如何使用组件? 核心实现方法 关于分布式本地缓存失效 前言 在生产中已有实践,本组件仅做个人学习交流分享使用.github:https://github.com/axinSoochow/redis-caffeine-cache-starter个人水平有限,欢迎大家在评论区轻喷. 所谓二级缓存 缓存就是将数据从读取较慢的介质上读取出来放到读取较快的介质上,如磁盘-->内存. 平时我们会将数据存储到磁盘上,如:数据库.如果每次都从数据库里去读取,会因为

  • spring boot+spring cache实现两级缓存(redis+caffeine)

    spring boot中集成了spring cache,并有多种缓存方式的实现,如:Redis.Caffeine.JCache.EhCache等等.但如果只用一种缓存,要么会有较大的网络消耗(如Redis),要么就是内存占用太大(如Caffeine这种应用内存缓存).在很多场景下,可以结合起来实现一.二级缓存的方式,能够很大程度提高应用的处理效率. 内容说明: 缓存.两级缓存 spring cache:主要包含spring cache定义的接口方法说明和注解中的属性说明 spring boot

  • 详细介绍高性能Java缓存库Caffeine

    1.介绍 在本文中,我们来看看Caffeine- 一个高性能的 Java 缓存库. 缓存和 Map 之间的一个根本区别在于缓存可以回收存储的 item. 回收策略为在指定时间删除哪些对象.此策略直接影响缓存的命中率 - 缓存库的一个重要特征. Caffeine 因使用 Window TinyLfu 回收策略,提供了一个近乎最佳的命中率. 2.依赖 我们需要在 pom.xml 中添加 caffeine 依赖: <dependency> <groupId>com.github.ben-

  • 轻松了解java中Caffeine高性能缓存库

    目录 轻松lCaffeine 1.依赖 2.写入缓存 2.1.手动写入 2.2.同步加载 2.3.异步加载 3.缓存值的清理 3.1.基于大小的清理 3.2.基于时间的清理 3.3.基于引用的清理 4.缓存刷新 5.统计 轻松lCaffeine 1.依赖 我们需要将Caffeine依赖添加到我们的pom.xml中: <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId&g

  • Gradle Build Cache引发的Task缓存编译问题

    目录 前言 基础知识 Cacheable tasks TaskOutput 有趣的编译问题 问题分析 最后 前言 前一阵子公司内部卷了一篇文章大家有兴趣的可以看下,大概把我们编译优化的原理介绍了下,当然其中还有些技术细节相关的并没有写. 哔哩哔哩Android编译优化. 基础知识 Gradle 构建缓存是一种缓存机制,旨在通过重用其他构建产生的输出来节省时间.构建缓存通过存储(本地或远程)构建输出并允许构建在确定输入没有更改时从缓存中获取这些输出来工作,从而避免了重新生成它们的昂贵工作. 使用构

  • 解决Mac OS X 自带PHP环境gd库扩展缺少freetype的问题

    验证码真的出来喽! curl -s http://php-osx.liip.ch/install.sh | bash -s 7.0 以上这篇解决Mac OS X 自带PHP环境gd库扩展缺少freetype的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们. 您可能感兴趣的文章: PHP GD库添加freetype拓展的方法

随机推荐