golang 性能优化之 bitset 代替 hashset

本文介绍如何使用bitset替代hashset进行性能优化,特别是在广告定向等高频率调用场景中,通过位运算实现元素的快速查找,相较于传统hashset提升了20多倍的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hashset 是一种非常高效的数据结构,插入和查询的复杂度都是 O(1),基本上能满足大部分场景的性能需求,但在一些特殊的场景下,频次非常高的调用依然会成为性能瓶颈(用 pprof 分析),比如广告里面的定向逻辑,在一次请求中过滤逻辑可能会执行上千次,而其中有些过滤刚好都是一些枚举值,比如性别定向,年龄定向等等,对于这种可以用枚举表示的值可以用 bitset 优化,能有20多倍的性能提升

bitset 的本质也是一种 hashset,只不过哈希桶用一个 uint64 来表示了,uint64 中的每一位用来代表一个元素是否存在,如果为1表示存在,为0表示不存在,而插入和查询操作就变成了位运算

bitset 实现

bitset 的实现比较容易,下面这个是一个只支持枚举值不超过64的版本,当然也可以拓展到任意长度,使用一个 uint64 数组作为 hash 桶即可

type BitSet struct {
    bit uint64
}

func (bs *BitSet) Add(i uint64) {
    bs.bit |= 1 << i
}

func (bs *BitSet) Del(i uint64) {
    bs.bit &= ^(1 << i)
}

func (bs BitSet) Has(i uint64) bool {
    return bs.bit&(1<<i) != 0
}

性能测试

func BenchmarkSetContains(b *testing.B) {
    bitset := NewBitSet()
    hashset := map[uint64]struct{}{}
    for _, i := range []uint64{1, 2, 4, 10} {
        bitset.Add(i)
        hashset[i] = struct{}{}
    }

    b.Run("bitset", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            for i := uint64(0); i < uint64(10); i++ {
                _ = bitset.Has(i)
            }
        }
    })

    b.Run("hashset", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            for i := uint64(0); i < uint64(10); i++ {
                _, _ = hashset[i]
            }
        }
    })
}
BenchmarkSetContains/bitset-8           500000000            3.81 ns/op        0 B/op          0 allocs/op
BenchmarkSetContains/hashset-8          20000000            89.4 ns/op         0 B/op          0 allocs/op

可以看到 bitset 相比 hashset 有20多倍的性能提升

参考链接

转载请注明出处
本文链接:http://www.hatlonely.com/2018/04/12/golang-性能优化之-bitset-代替-set/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值