美文网首页GolangGo语言Golang 优化之路
Golang 优化之路——空结构

Golang 优化之路——空结构

作者: Cyeam | 来源:发表于2017-05-09 14:10 被阅读201次

写在前面

开发 hashset 常用的套路:

map[int]int8

map[int]bool

我们一般只用 map 的键来保存数据,值是没有用的。所以来缓存集合数据会造成内存浪费。

空对象

空对象是个神奇的东西。它指的是没有字段的结构类型。

type Q struct{}

它牛逼的地方在于:

  • 可以和普通结构一样操作

    var a = []struct{}{struct{}{}}
    
    fmt.Println(len(a)) // prints 1
    
  • 不占用空间

    var s struct{}
    
    fmt.Println(unsafe.Sizeof(s)) // prints 0
    
  • 声明两个空对象,它们指向同一个地址

    type A struct{}
    
    a := A{}
    
    b := A{}
    
    fmt.Println(&a == &b) // prints true
    

造成这个结果的原因是 Golang 的编译器会把这种空对象都当成runtime.zerobase处理。

var zerobase uintptr

hashset

有了上面的介绍,就可以利用空结构来优化 hashset 了。

var itemExists = struct{}{}

type Set struct {
    items map[interface{}]struct{}
}

func New() *Set {
    return &Set{items: make(map[interface{}]struct{})}
}

func (set *Set) Add(item interface{}) {
    set.items[item] = itemExists
}

func (set *Set) Remove(item interface{}) {
    delete(set.items, item)
}

func (set *Set) Contains(item interface{}) bool {
    if _, contains := set.items[item]; !contains {
        return false
    }
    return true
}

一个简易的 hashset 实现就完成了。

性能比较

func BenchmarkIntSet(b *testing.B) {
    var B = NewIntSet(3)
    B.Set(10).Set(11)
    for i := 0; i < b.N; i++ {
        if B.Exists(1) {

        }
        if B.Exists(11) {

        }
        if B.Exists(1000000) {

        }
    }
}

func BenchmarkMap(b *testing.B) {
    var B = make(map[int]int8, 3)
    B[10] = 1
    B[11] = 1
    for i := 0; i < b.N; i++ {
        if _, exists := B[1]; exists {

        }
        if _, exists := B[11]; exists {

        }
        if _, exists := B[1000000]; exists {

        }
    }
}

BenchmarkIntSet-2       50000000                35.3 ns/op             0 B/op          0 allocs/op
BenchmarkMap-2          30000000                41.2 ns/op             0 B/op          0 allocs/op

结论

  • 性能,有些提升,但不是特别明显。尤其是线上压力不大的情况性能应该不会有明显变化;

  • 内存占用。我们的服务缓存较多、占用内存较大,通过这个优化实测可以减少 1.6 GB 的空间。不过这个优化的空间取决于数据量。


参考文献

相关文章

  • Golang 优化之路——空结构

    写在前面 开发 hashset 常用的套路: 我们一般只用 map 的键来保存数据,值是没有用的。所以来缓存集合数...

  • golang

    Golang 优化之路——自己造一个日志轮子 据我观察,基本没有人在用 Golang 原生的 log 包写日志。今...

  • Golang 优化之路——bitset

    写在前面 开发过程中会经常处理集合这种数据结构,简单点的处理方法都是使用内置的map实现。但是如果要应对大量数据,...

  • golang 日志相关

    先收集,以后再弄:Golang 优化之路——自己造一个日志轮子日志切割:lumberjack开源日志:zap,速度...

  • Golang对象复用静态代码检查工具

    一、对象复用 在高并发的场景下使用golang,优化GC都会无法回避的问题。搜索「golang 垃圾回收优化」出来...

  • Golang 优化之路——HTTP长连接

    写在前面 压测的是否发现服务端TIME_WAIT状态的连接很多。 TIME_WAIT状态多,简单的说就是服务端主动...

  • Go每日精选(2019-06-17)

    1.golang fmt递归引起stack overflow异常 2.golang新版如何优化sync.pool锁...

  • 结构 struct golang

    原文链接:结构struct-GOLANG

  • Golang 专栏

    简介 整理 Golang 相关文章,方便大家阅读。 目录 golang 编程规范 - 项目目录结构[https:/...

  • golang

    golang携程调度,runtime包 golang内存模型 csp原理 context的原理 slice底层结构...

网友评论

  • 煎鱼不可能有BUG:“我们一般只用 map 的键来保存数据,值是没有用的。”
    不妨大概说说这个情况下的例子? :smile:
    Cyeam:@煎鱼教教主 当程序需要用到集合set时候

本文标题:Golang 优化之路——空结构

本文链接:https://www.haomeiwen.com/subject/nenbtxtx.html