环境:GO1.19.3,windows10

先说结论:

对于map[sting]* Object

1)如果结构体Object中含有指针或者string类型,GC耗时比较多,尤其是1000万条以后;应该使用bigCache等无GC组件存储;

2)如果Object中只有整形等,1亿条以下,性能比bigcache好很多;

之前看了一篇帖子,主要内容是讲大量的map中不要存储对象指针或者带指针的类型,会造成GC的代价比较大;

Go语言使用 map 时尽量不要在 big map 中保存指针 - 简书

type urlInfo struct {url       stringCount     uint64LastCount uint64
}func MapWithPointer() {const N = 100000000m := make(map[string]*urlInfo)for i := 0; i < N; i++ {n := strconv.Itoa(i)info := urlInfo{n, uint64(i), uint64(i + 1)}m[n] = &info}now := time.Now()runtime.GC() // 手动触发 GCfmt.Printf("With a map of strings, GC took: %s\n", time.Since(now))_ = m["0"] // 引用一下防止被 GC 回收掉
}

我测试了一下,果然是这样的,当1000万条数据时,GC1秒多,如果是1亿条数据,GC会达到14秒,这样程序就完全不能用了!!!这时需要考虑使用freeCache和BigCache等组件;

但是,如果是不存储字符串的结构体,仅仅使用字符串作为键值,测试结果发现map还是可以用的,

我的需求是需要大概1000万个计数器,使用字符串作为键值,

计数器使用一个比较简单的类:

type Counter struct {Count     int64LastCount int64
}

一、先简单的对比map[string]Counter 和map[string]*Counter的性能,

方法:

1)分别写入0-1000万编号为字符串的对象初始值;

2)随便找一个编号的对象做+1操作,执行700万次;计时;

3)手动执行GC操作,计时;

结果:

1)存对象:耗时82ms, GC 耗时: 10.0976ms

2)存指针:耗时62ms,  GC 耗时: 10.0926ms

分析原因:map中对象无法直接更改,读写需要内存拷贝耗时更多,但是GC并没有发现使用指针消耗更多的资源;

备注:测试条目增加到1亿条数据后,发现存取无大影响,GC耗时140毫秒左右;

二、对比bigCache

如果使用BigCache:GitHub - allegro/bigcache: Efficient cache for gigabytes of data written in Go.

执行类似操作,执行700万次读写一个18字节的字节流,

结果:

操作耗时1592毫秒, GC 耗时: 11.0851ms

结论:在单线程情况下,bigCache并没有发现更大的优势;这里GC应该与bigCache存储的内容关系不大;

按照网上的测试,Go中的缓存现状(BigCache&FreeCache&GroupCache 缓存框架对比) - 简书

bigCache在40个并发的情况下性能有很大的提升:

但是,如果是性能差别如此明显的情况下,并发环境下我更倾向于对map的锁进行分片,比如concurrent-map,使用了一个泛型的map存储多个小map,每个小map分别加锁,真正存储数据。

GitHub - orcaman/concurrent-map: a thread-safe concurrent map for go

备注:有人写了一个帖子,使用gob执行对象的序列化,这样可以bigCache就可以读写任意类型的对象,但是:gob的性能非常差,并不可取,如果存储的类型比较简单完全可以自己编写序列化与反序列化函数,或者使用json或者使用protobuf,评测见:go语言序列化json/gob/msgp/protobuf性能对比 - 知乎

func main() {testBigRaw()//MapWithPointer()//MapWithoutPointer()//testMap1()//testMap2()
}func testBigRaw() {cache, _ := bigcache.NewBigCache(bigcache.Config{Shards:             16,LifeWindow:         time.Second * 3600,CleanWindow:        time.Hour * 24,MaxEntriesInWindow: 1000 * 10 * 60,MaxEntrySize:       500,Verbose:            false,HardMaxCacheSize:   1024,StatsEnabled:       true,})for i := 0; i < 10000000; i++ {key := strconv.Itoa(i)cache.Set(key, []byte("value1 and value2"))}timeUnixNano1 := time.Now().UnixMilli()// 100万次更新for i := 0; i < 7000000; i++ {cache.Get("111")cache.Set("111", []byte("value1 and value3"))}timeUnixNano2 := time.Now().UnixMilli()delta := timeUnixNano2 - timeUnixNano1fmt.Println(delta)now := time.Now()runtime.GC() // 手动触发 GCfmt.Printf("With a map of strings, GC took: %s\n", time.Since(now))entry, _ := cache.Get("my-unique-key")fmt.Println(string(entry))
}func testMap1() {cache := make(map[string]Counter)for i := 0; i < 10000000; i++ {key := strconv.Itoa(i)cache[key] = Counter{0, 0}}timeUnixNano1 := time.Now().UnixMilli()// 100万次更新for i := 0; i < 7000000; i++ {res, _ := cache["111"]res.Count += 1cache["111"] = res}timeUnixNano2 := time.Now().UnixMilli()delta := timeUnixNano2 - timeUnixNano1fmt.Println(delta)now := time.Now()runtime.GC() // 手动触发 GCfmt.Printf("With a map of strings, GC took: %s\n", time.Since(now))}func testMap2() {cache := make(map[string]*Counter)for i := 0; i < 10000000; i++ {key := strconv.Itoa(i)cache[key] = &Counter{0, 0}}timeUnixNano1 := time.Now().UnixMilli()// 100万次更新for i := 0; i < 7000000; i++ {res, _ := cache["111"]res.Count += 1}timeUnixNano2 := time.Now().UnixMilli()delta := timeUnixNano2 - timeUnixNano1fmt.Println(delta)now := time.Now()runtime.GC() // 手动触发 GCfmt.Printf("With a map of strings, GC took: %s\n", time.Since(now))}

golang单线程对比map与bigCache小对象存取性能差别相关推荐

  1. golang orm对比

    golang orm对比 golang https://segmentfault.com/a/1190000015606291 各主流的golang orm介绍 当前较为主流/活跃的orm有gorm. ...

  2. Golang 中使用 JSON 的一些小技巧 陶文 陶文 3 个月前 有的时候上游传过来的字段是string类型的,但是我们却想用变成数字来使用。 本来用一个json:,string 就可以支持了

    Golang 中使用 JSON 的一些小技巧 陶文 3 个月前 有的时候上游传过来的字段是string类型的,但是我们却想用变成数字来使用. 本来用一个json:",string" ...

  3. JVM中GC小对象配置

    小对象配置 -XX:+UseTLAB 表示,使用TLAB TLAB Thread Local Allocation Buffer 线程本地分配缓存 一个线程专用的内存分配区域,为了加速对象分配 每一个 ...

  4. Java小对象的解决之道——对象池(Object Pool)的设计与应用

    一.概述 面向对象编程是软件开发中的一项利器,现已经成为大多数编程人员的编程思路.很多高级计算机语言也对这种编程模式提供了很好的支持,例如C++.Object Pascal.Java等.曾经有大量的软 ...

  5. PS 2019 Mac版 自学入门系列(九)—— 复制小对象和纹理

    学习内容--使用仿制图章工具以复制小对象和纹理 目录 学习内容--使用仿制图章工具以复制小对象和纹理 1. 图像处理前后对比 2. 使用仿制图章工具 3. 图像处理结果 1. 图像处理前后对比 处理目 ...

  6. HBase技术与应用实践 | HBase2.0重新定义小对象实时存取

    本次分享来自中国HBase技术社区第七届MeetUp成都站,分享嘉宾天引 阿里巴巴 技术专家专注在大数据领域,拥有多年分布式.高并发.大规模系统的研发与实践经验,先后参与HBase.Phoenix.L ...

  7. Slab,小对象也能搞出大事情

    排查内存使用(泄露.耗尽)问题的一个的技巧是,区分"批发商"和"零售商"这两类不同的内存管理机制.这里的"批发商",指的是按页面管理并分配内 ...

  8. Redis存储优化--小对象压缩

    小对象压缩 Redis是一种内存数据库,内存是计算机中一种比较宝贵的资源,如果我们不注意节约,Redis很可能出现内存不足,最终导致崩溃.Redis为了优化数据结构的内存占用,增加了非常多的优化点,这 ...

  9. 记一次golang中sync.Map并发创建、读取的问题

    记一次golang中sync.Map并发创建.读取的问题  cunfate https://www.jianshu.com/p/f472e79909bc 背景: 我们有一个用go做的项目,其中用到了z ...

  10. 【便签纸】记录一下对比excel列表的小工具代码

    记录一下对比excel列表的小工具代码,方便下次取用,环境python2. #!/usr/bin/env python # -*- coding: UTF-8 -*-import sys import ...

最新文章

  1. 制造业采购审批流程设计示例
  2. 工作周报:2011-11-14至2011-11-18
  3. redis和memcache的高可用的探索
  4. 安装Windows10,Ubuntu双系统14.04LTS记录
  5. matlab 28m35,F28M35H52C
  6. CF444C-DZY Loves Colors【线段树,set】
  7. 关于xml文件 xsi:schemaLocation
  8. python面试常问题解答_10个Python面试常问的问题
  9. 基于设备树的TQ2440 DMA学习(3)—— DMA控制器驱动
  10. AWS推出OpenJDK长期支持版本Amazon Corretto
  11. GB28181国标流媒体服务(LiveGBS)-支持海康8700等联网网关通过接入实现web端无插件直播
  12. 专题一:Labview表格控件 及 应用(三)在表格中插入一行数据
  13. mysql数据驱动问题hour_day_of 0 ->1
  14. 基于matlab的可见光成像通信OOK解调
  15. Codeforces Round #614 (Div. 2) A题ConneR and the A.R.C. Markland-N
  16. Win7如何查看自己得Win7版本号
  17. tiptop 编译运行_TIPTOP MPS(amsp500)运行流程
  18. 数字字符串转换成数值
  19. 基于 Impala 的高性能数仓实践之物化视图服务
  20. java string 去掉某个字符_JAVA String 如何去掉指定字符

热门文章

  1. python更换证件照底色
  2. 480位禅宗大德悟道因缘
  3. 词频统计 matlab,5年cvpr论文词频分析,今年最火词——深度学习
  4. 沟通技巧-《非暴力沟通》书中的精髓:改变对待冲突和矛盾的看法,通过非暴力沟通的方式,可以使生活更加美好。
  5. excel转置怎么操作_EXCEL/WPS如何快速将一行转置成一列,一列转置成一行?
  6. Codeforces 754D. Fedor and coupons
  7. 准备工作-PPT母版
  8. 20021年还需要学C语言吗?C语言成为专家的路径、方法、书籍推荐
  9. Win10环境VMware开WinXP虚拟机CPU占用100%
  10. html中title属性和alt属性的区别