golang高性能自适应基数树实现插件库go-adaptive-radix-tree的使用
Golang高性能自适应基数树实现插件库go-adaptive-radix-tree的使用
介绍
这是一个Go语言实现的自适应基数树(Adaptive Radix Tree)库。
主要特性:
- 查找性能超过高度优化的替代方案
- 支持高效的插入和删除操作
- 空间效率高
- 性能可与哈希表媲美
- 保持数据有序,支持范围扫描和前缀查找等额外操作
- 搜索/插入/删除操作的时间复杂度为O(k),k是键的长度
- 支持查找最小/最大值
- 有序迭代
- 基于前缀的迭代
- 支持反向迭代
- 支持包含空字节的键,任何字节数组都可以作为键
使用示例
package main
import (
"fmt"
art "github.com/plar/go-adaptive-radix-tree/v2"
)
func main() {
// 初始化一个新的自适应基数树
tree := art.New()
// 向树中插入键值对
tree.Insert(art.Key("apple"), "A sweet red fruit")
tree.Insert(art.Key("banana"), "A long yellow fruit")
tree.Insert(art.Key("cherry"), "A small red fruit")
tree.Insert(art.Key("date"), "A sweet brown fruit")
// 通过键搜索值
if value, found := tree.Search(art.Key("banana")); found {
fmt.Println("Found:", value)
} else {
fmt.Println("Key not found")
}
// 按升序遍历树
fmt.Println("\nAscending order iteration:")
tree.ForEach(func(node art.Node) bool {
fmt.Printf("Key: %s, Value: %s\n", node.Key(), node.Value())
return true
})
// 使用反向遍历按降序遍历树
fmt.Println("\nDescending order iteration:")
tree.ForEach(func(node art.Node) bool {
fmt.Printf("Key: %s, Value: %s\n", node.Key(), node.Value())
return true
}, art.TraverseReverse)
// 遍历具有特定前缀的键
fmt.Println("\nIteration with prefix 'c':")
tree.ForEachPrefix(art.Key("c"), func(node art.Node) bool {
fmt.Printf("Key: %s, Value: %s\n", node.Key(), node.Value())
return true
})
}
// 预期输出:
// Found: A long yellow fruit
//
// Ascending order iteration:
// Key: apple, Value: A sweet red fruit
// Key: banana, Value: A long yellow fruit
// Key: cherry, Value: A small red fruit
// Key: date, Value: A sweet brown fruit
//
// Descending order iteration:
// Key: date, Value: A sweet brown fruit
// Key: cherry, Value: A small red fruit
// Key: banana, Value: A long yellow fruit
// Key: apple, Value: A sweet red fruit
//
// Iteration with prefix 'c':
// Key: cherry, Value: A small red fruit
从v1迁移到v2
- 更新import语句:
from `art "github.com/plar/go-adaptive-radix-tree"`
to `art "github.com/plar/go-adaptive-radix-tree/v2"`
- 更新go模块依赖:
$ go get github.com/plar/go-adaptive-radix-tree/v2
$ go mod tidy
如果你实现了自己的Tree接口,需要更新以下方法以支持options:
ForEachPrefix(keyPrefix Key, callback Callback, options ...int)
性能
性能基准测试使用了从不同项目中提取的数据集:
- "Words"数据集包含235,886个英文单词
- "UUIDs"数据集包含100,000个UUID
- "HSK Words"数据集包含4,995个单词
性能对比表:
go-adaptive-radix-tree | # | Average time | Bytes per operation | Allocs per operation |
---|---|---|---|---|
Tree Insert Words | 9 | 117,888,698 ns/op | 37,942,744 B/op | 1,214,541 allocs/op |
Tree Search Words | 26 | 44,555,608 ns/op | 0 B/op | 0 allocs/op |
Tree Insert UUIDs | 18 | 59,360,135 ns/op | 18,375,723 B/op | 485,057 allocs/op |
Tree Search UUIDs | 54 | 21,265,931 ns/op | 0 B/op | 0 allocs/op |
go-art | # | Average time | Bytes per operation | Allocs per operation |
---|---|---|---|---|
Tree Insert Words | 5 | 272,047,975 ns/op | 81,628,987 B/op | 2,547,316 allocs/op |
Tree Search Words | 10 | 129,011,177 ns/op | 13,272,278 B/op | 1,659,033 allocs/op |
Tree Insert UUIDs | 10 | 140,309,246 ns/op | 33,678,160 B/op | 874,561 allocs/op |
Tree Search UUIDs | 20 | 82,120,943 ns/op | 3,883,131 B/op | 485,391 allocs/op |
要查看更多基准测试,可以运行:
$ ./make qa/benchmarks
更多关于golang高性能自适应基数树实现插件库go-adaptive-radix-tree的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高性能自适应基数树实现插件库go-adaptive-radix-tree的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
go-adaptive-radix-tree 高性能自适应基数树实现
go-adaptive-radix-tree (简称 ART) 是一个 Golang 实现的高性能自适应基数树库,它是基数树的一种优化变体,特别适合需要高性能键值存储的场景。
特性概述
- 自适应节点大小,根据子节点数量自动调整
- 内存效率高,比传统基数树更节省空间
- 支持并发安全操作
- 提供前缀搜索、范围查询等高级功能
- 性能优于标准哈希表和普通树结构
安装
go get github.com/plar/go-adaptive-radix-tree
基本使用示例
package main
import (
"fmt"
art "github.com/plar/go-adaptive-radix-tree"
)
func main() {
// 创建新树
tree := art.New()
// 插入键值对
tree.Insert(art.Key("Hello"), "World")
tree.Insert(art.Key("Golang"), "Rocks")
tree.Insert(art.Key("Radix"), "Tree")
// 查找
value, found := tree.Search(art.Key("Golang"))
if found {
fmt.Printf("Found: %v\n", value) // 输出: Found: Rocks
}
// 删除
tree.Delete(art.Key("Hello"))
// 遍历所有键值对
tree.ForEach(func(node art.Node) bool {
fmt.Printf("Key: %s, Value: %v\n", node.Key(), node.Value())
return true
})
}
高级功能
前缀搜索
// 插入一些测试数据
tree.Insert(art.Key("api:v1:users"), "usersV1")
tree.Insert(art.Key("api:v1:products"), "productsV1")
tree.Insert(art.Key("api:v2:users"), "usersV2")
// 搜索所有api:v1前缀的键
results := []string{}
tree.ForEachPrefix(art.Key("api:v1:"), func(node art.Node) bool {
results = append(results, node.Value().(string))
return true
})
fmt.Println(results) // 输出: [usersV1 productsV1]
范围查询
tree.Insert(art.Key("apple"), 1)
tree.Insert(art.Key("banana"), 2)
tree.Insert(art.Key("cherry"), 3)
tree.Insert(art.Key("date"), 4)
// 查询a-c之间的键
tree.ForEachRange(art.Key("a"), art.Key("d"), func(node art.Node) bool {
fmt.Printf("%s: %v\n", node.Key(), node.Value())
return true
})
并发安全使用
import "sync"
func main() {
tree := art.New()
var wg sync.WaitGroup
// 并发插入
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := art.Key(fmt.Sprintf("key%d", i))
tree.Insert(key, i)
}(i)
}
wg.Wait()
// 验证插入结果
fmt.Println("Tree size:", tree.Size())
}
性能考虑
- 批量操作:对于批量插入,考虑预排序键可以提升性能
- 键设计:使用较短的公共前缀可以最大化ART的优势
- 内存使用:ART比标准哈希表更节省内存,特别是键有公共前缀时
实际应用场景
- 路由系统(如HTTP路由器)
- 数据库索引
- 内存键值存储
- 自动补全系统
- IP路由表
与标准map的对比
func benchmark() {
// 测试数据
keys := make([]string, 1000000)
for i := range keys {
keys[i] = fmt.Sprintf("key:%d:%d:%d", i, i*2, i*3)
}
// 标准map测试
start := time.Now()
m := make(map[string]interface{})
for _, k := range keys {
m[k] = true
}
fmt.Println("Map insert:", time.Since(start))
// ART测试
start = time.Now()
tree := art.New()
for _, k := range keys {
tree.Insert(art.Key(k), true)
}
fmt.Println("ART insert:", time.Since(start))
}
在键具有公共前缀的情况下,ART通常表现出更好的性能,特别是随着数据量增长时。
注意事项
- 键必须是[]byte类型,使用art.Key()进行转换
- 默认情况下非并发安全,并发访问需要外部同步
- 对于完全随机的键,标准哈希表可能性能更好
go-adaptive-radix-tree是一个功能强大且高效的库,特别适合处理具有公共前缀的键的场景。它的设计平衡了内存使用和查询性能,是许多高性能应用的理想选择。