zoukankan      html  css  js  c++  java
  • Golang 优化之路-空结构[转]

    写在前面

    开发 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 的空间。不过这个优化的空间取决于数据量。

    参考文献

  • 相关阅读:
    Linux的安装(虚拟机环境)与基础配置
    爬虫之proxy(代理)
    爬虫之UserAgent
    爬虫之urllib.error模块
    【React自制全家桶】五、React组件的生命周期函数详解
    【React自制全家桶】四、React中state与props的分析与比较
    【React自制全家桶】三、React使用ref操作DOM与setState遇到的问题
    【React自制全家桶】二、分析React的虚拟DOM和Diff算法
    小程序API:wx.showActionSheet 将 itemList动态赋值
    解决json_encode中文乱码问题
  • 原文地址:https://www.cnblogs.com/logo-fox/p/6985598.html
Copyright © 2011-2022 走看看