脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - golang cache带索引超时缓存库实战示例

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

2022-11-16 14:09w008p Golang

这篇文章主要为大家介绍了golang cache带索引超时缓存库实战示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

正文

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

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

example

定义泛型函数

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

Filter 函数

?
1
2
3
4
5
6
7
8
9
10
11
// 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
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 测试[]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 函数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 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 函数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 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 结构

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 用辅助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)
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
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 结构

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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 去重

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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 结构

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 测试数据
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`,
    }
)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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索引超时缓存库的资料请关注服务器之家其它相关文章!

原文链接:https://studygolang.com/articles/35840

延伸 · 阅读

精彩推荐
  • GolangGoland使用Go Modules创建/管理项目的操作

    Goland使用Go Modules创建/管理项目的操作

    这篇文章主要介绍了Goland使用Go Modules创建/管理项目的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    deantzzz8172021-06-21
  • Golanggolang实现http服务器处理静态文件示例

    golang实现http服务器处理静态文件示例

    这篇文章主要介绍了golang实现http服务器处理静态文件的方法,涉及Go语言基于http协议处理文件的相关技巧,需要的朋友可以参考下 ...

    脚本之家8032020-04-29
  • Golanggorm整合进go-zero的实现方法

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

    go-zero提供的代码生成器里面,没有提供orm框架操作,但是提供了遍历的缓存操作,所以可以利用gorm当作一个sql语句的生成器,把生成后的sql语句放到go-z...

    jiangxiaoju9122022-09-07
  • GolangGO项目配置与使用的方法步骤

    GO项目配置与使用的方法步骤

    本文主要介绍了GO项目配置与使用的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随...

    langlang而Go5492022-10-13
  • Golang如何利用golang运用mysql数据库

    如何利用golang运用mysql数据库

    这篇文章主要介绍了如何利用golang运用mysql数据库,文章对依赖包、db对象注入ApiRouter等内容,需要的小伙伴可以参考一下...

    峰啊疯了10532022-09-06
  • Golanggo语言方法集为类型添加方法示例解析

    go语言方法集为类型添加方法示例解析

    这篇文章主要为大家介绍了go语言方法集以及为类型添加方法示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪...

    Jeff的技术栈8092022-09-19
  • Golang利用Golang解析json数据的方法示例

    利用Golang解析json数据的方法示例

    Go提供了原生的JSON库,并且与语言本身有效的集成在了一起。下面这篇文章将给大家介绍关于利用Golang解析json数据的方法,文中给出了详细的示例代码供大...

    小谈3082020-05-08
  • Golang解决Goland中利用HTTPClient发送请求超时返回EOF错误DEBUG

    解决Goland中利用HTTPClient发送请求超时返回EOF错误DEBUG

    这篇文章主要介绍了解决Goland中利用HTTPClient发送请求超时返回EOF错误DEBUG,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    PrnyNing11582021-02-25