golang高性能零分配SIMD位图/位集处理插件库bitmap的使用
Golang高性能零分配SIMD位图/位集处理插件库bitmap的使用
简介
这是一个高性能的位图(Bitmap/Bitset)实现,底层使用[]uint64
切片,专为密集的小型或中型集合设计。该实现通过避免堆分配、展开循环和在汇编中实现SIMD向量化来追求高性能。
主要特性
- 所有重要方法都优化为零堆分配
- 使用**向量化指令(SIMD)**优化某些操作如布尔代数
- 支持布尔代数运算,非常适合实现位图索引
- 支持位计数操作如
Min()
、Max()
、Count()
等 - 支持使用展开循环快速迭代设置为1的位
- 支持基于用户定义谓词的原地过滤
- 支持二进制编码,可读写且有无拷贝的切片转换
- 通过提供
Clone()
和Clear()
操作支持可重用性
使用示例
基本使用
import "github.com/kelindar/bitmap"
func main() {
var books bitmap.Bitmap
// 设置位
books.Set(300) // 设置第300位为1
books.Set(400) // 设置第400位为1
books.Set(600) // 设置第600位为1(自动调整大小)
// 检查位
has300 := books.Contains(300) // 返回true
has301 := books.Contains(301) // 返回false
// 清除位
books.Remove(400) // 清除第400位
// 最小/最大/计数
min, ok := books.Min() // 返回300
max, ok := books.Max() // 返回600
count := books.Count() // 返回2
// 布尔代数
var other bitmap.Bitmap
other.Set(300)
books.And(other) // 交集
count = books.Count() // 现在返回1
}
布尔代数示例
// 假设我们有三个位图
books := bitmapFor("books") // 所有书籍
recent := bitmapFor("books_recent") // 最近出版的书籍
ebooks := bitmapFor("books_has_ebook") // 有电子书的书籍
// 找出最近出版且有电子书的书籍
books.And(recent)
books.And(ebooks)
单一位操作
var books bitmap.Bitmap
books.Set(3) // 设置第3位为'1'
hasBook := books.Contains(3) // 返回'true'
books.Remove(3) // 设置第3位为'0'
位计数和搜索
// 计算设置为'1'的位数
numBooks := books.Count()
// 查找第一个和最后一个设置为1的位
min, ok := books.Min() // 第一个设置为1的位
max, ok := books.Max() // 最后一个设置为1的位
// 查找第一个和最后一个设置为0的位
minZero, ok := books.MinZero()
maxZero, ok := books.MaxZero()
迭代和过滤
// 迭代位图中的位
books.Range(func(x uint32) bool {
println(x)
return true // 返回false停止迭代
})
// 过滤位图 - 只保留偶数位
books.Filter(func(x uint32) bool {
return x % 2 == 0
})
性能基准
以下基准测试是在一个预分配的100,000元素位图上运行的,大约50%的位设置为1。
cpu: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
BenchmarkBitmap/set-8 552331321 4.319 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/remove-8 1000000000 1.621 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/contains-8 1000000000 1.309 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/clear-8 26083383 90.45 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/ones-8 6751939 347.9 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/min-8 757831477 3.137 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/max-8 1000000000 1.960 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/min-zero-8 776620110 3.081 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/max-zero-8 1000000000 1.536 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/count-8 6071037 382.5 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/count-to-8 82777459 28.85 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/clone-8 20654008 111.5 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/and-8 16813963 143.6 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/andnot-8 16961106 141.9 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/or-8 16999562 141.7 ns/op 0 B/op 0 allocs/op
BenchmarkBitmap/xor-8 16954036 144.7 ns/op 0 B/op 0 allocs/op
BenchmarkRange/range-8 18225 131908 ns/op 0 B/op 0 allocs/op
BenchmarkRange/filter-8 25636 93630 ns/op 0 B/op 0 allocs/op
完整示例
package main
import (
"fmt"
"github.com/kelindar/bitmap"
)
func main() {
// 创建一个位图
var bm bitmap.Bitmap
// 设置一些位
bm.Set(1)
bm.Set(3)
bm.Set(5)
bm.Set(7)
bm.Set(300) // 自动扩展
// 检查位
fmt.Println("Contains 1:", bm.Contains(1)) // true
fmt.Println("Contains 2:", bm.Contains(2)) // false
// 计数
fmt.Println("Count:", bm.Count()) // 5
// 最小/最大
min, _ := bm.Min()
max, _ := bm.Max()
fmt.Println("Min:", min, "Max:", max) // Min: 1 Max: 300
// 迭代
fmt.Println("Iterating:")
bm.Range(func(x uint32) bool {
fmt.Println(x)
return true
})
// 布尔运算
var other bitmap.Bitmap
other.Set(3)
other.Set(5)
other.Set(100)
// 交集
bm.And(other)
fmt.Println("After AND, count:", bm.Count()) // 2 (3 and 5)
// 克隆
clone := bm.Clone()
fmt.Println("Clone count:", clone.Count()) // 2
// 清除
bm.Clear()
fmt.Println("After clear, count:", bm.Count()) // 0
}
这个库非常适合需要高性能位操作的场景,特别是作为索引或过滤大量数据时。
更多关于golang高性能零分配SIMD位图/位集处理插件库bitmap的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高性能零分配SIMD位图/位集处理插件库bitmap的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang高性能位图处理库bitmap使用指南
bitmap是一个专为Golang设计的高性能位集/位图处理库,它利用SIMD指令优化位操作,实现零内存分配的高效处理。下面我将详细介绍其核心功能和使用方法。
安装
go get github.com/bits-and-blooms/bitset
基本使用
创建位图
package main
import (
"fmt"
"github.com/bits-and-blooms/bitset"
)
func main() {
var b bitset.BitSet
// 设置位
b.Set(10) // 将第10位设为1
b.Set(100)
// 测试位
if b.Test(10) {
fmt.Println("第10位已设置")
}
// 清除位
b.Clear(10)
// 获取长度
fmt.Println("位图长度:", b.Len())
// 统计设置位数
fmt.Println("设置位数:", b.Count())
}
高级特性
SIMD加速操作
bitmap库内部使用SIMD指令优化批量位操作:
func simdExample() {
b1 := bitset.New(1000)
b2 := bitset.New(1000)
// 设置一些位
for i := 0; i < 1000; i += 3 {
b1.Set(uint(i))
}
for i := 0; i < 1000; i += 5 {
b2.Set(uint(i))
}
// SIMD优化的交集
intersection := b1.Intersection(b2)
fmt.Println("交集元素:")
for i, e := intersection.NextSet(0); e; i, e = intersection.NextSet(i + 1) {
fmt.Println(i)
}
// SIMD优化的并集
union := b1.Union(b2)
fmt.Println("并集计数:", union.Count())
}
零分配操作
func zeroAllocExample() {
// 重用缓冲区减少分配
b := bitset.New(10000)
// 批量设置位(零分配)
positions := []uint{1, 2, 3, 4, 5, 100, 200, 300}
for _, pos := range positions {
b.Set(pos)
}
// 直接操作底层位切片(最高性能)
bitSlice := b.Bytes()
fmt.Printf("底层位数据长度: %d\n", len(bitSlice))
}
性能优化技巧
- 预分配大小:创建时指定足够大的容量避免扩容
// 预分配100万位的空间
b := bitset.New(1000000)
-
批量操作:使用Union/Intersection等批量方法而非单点操作
-
重用对象:复用bitset对象而非频繁创建销毁
-
直接访问底层数据:对性能关键路径使用Bytes()方法直接操作
实际应用示例
布隆过滤器实现
type BloomFilter struct {
bitset *bitset.BitSet
hashes []hash.Hash64
size uint
}
func NewBloomFilter(size uint) *BloomFilter {
return &BloomFilter{
bitset: bitset.New(size),
hashes: []hash.Hash64{fnv.New64(), fnv.New64a()},
size: size,
}
}
func (bf *BloomFilter) Add(data []byte) {
for _, h := range bf.hashes {
h.Reset()
h.Write(data)
index := h.Sum64() % uint64(bf.size)
bf.bitset.Set(uint(index))
}
}
func (bf *BloomFilter) Contains(data []byte) bool {
for _, h := range bf.hashes {
h.Reset()
h.Write(data)
index := h.Sum64() % uint64(bf.size)
if !bf.bitset.Test(uint(index)) {
return false
}
}
return true
}
注意事项
- 位图索引从0开始
- 线程不安全,并发访问需要加锁
- 超大位图(>10亿位)需要考虑内存占用
- 序列化时注意字节序问题
bitmap库通过SIMD指令和零分配设计,在性能上远超标准库的位操作实现,特别适合需要高频位操作的大规模数据处理场景。