golang高性能线程安全与非线程安全集合操作插件库golang-set的使用
golang高性能线程安全与非线程安全集合操作插件库golang-set的使用
golang-set 是为 Go 语言提供的一个高性能的集合操作库,支持线程安全和非线程安全两种实现方式。它提供了类似 Python 中 set 集合的功能,在 Go 原生不支持集合类型的情况下非常有用。
安装
使用 go get 命令安装该包:
go get github.com/deckarep/golang-set/v2
特性
- 基于泛型的实现(需要 Go 1.18 或更高版本)
- 提供两种实现:
- 非线程安全实现(性能优先)
- 线程安全实现(并发使用优先)
- 完整实现了 Python set 的功能
- 全面的单元测试和基准测试套件
使用示例
基本用法
package main
import (
"fmt"
mapset "github.com/deckarep/golang-set/v2"
)
func main() {
// 创建一个字符串集合
set := mapset.NewSet[string]()
set.Add("apple")
set.Add("banana")
set.Add("orange")
// 检查元素是否存在
fmt.Println(set.Contains("apple")) // 输出: true
fmt.Println(set.Contains("grape")) // 输出: false
// 获取集合大小
fmt.Println(set.Cardinality()) // 输出: 3
}
线程安全集合
package main
import (
"fmt"
mapset "github.com/deckarep/golang-set/v2"
)
func main() {
// 创建一个线程安全的字符串集合
safeSet := mapset.NewThreadSafeSet[string]()
safeSet.Add("one")
safeSet.Add("two")
safeSet.Add("three")
// 并发安全操作
fmt.Println(safeSet.Contains("two")) // 输出: true
}
集合操作
package main
import (
"fmt"
mapset "github.com/deckarep/golang-set/v2"
)
func main() {
set1 := mapset.NewSet[int](1, 2, 3, 4, 5)
set2 := mapset.NewSet[int](4, 5, 6, 7, 8)
// 并集
union := set1.Union(set2)
fmt.Println(union) // Set{1, 2, 3, 4, 5, 6, 7, 8}
// 交集
intersect := set1.Intersect(set2)
fmt.Println(intersect) // Set{4, 5}
// 差集
difference := set1.Difference(set2)
fmt.Println(difference) // Set{1, 2, 3}
// 对称差集
symDiff := set1.SymmetricDifference(set2)
fmt.Println(symDiff) // Set{1, 2, 3, 6, 7, 8}
}
自定义类型集合
package main
import (
"fmt"
mapset "github.com/deckarep/golang-set/v2"
)
type Person struct {
Name string
Age int
}
func main() {
// 创建自定义类型集合
people := mapset.NewSet[Person]()
people.Add(Person{"Alice", 30})
people.Add(Person{"Bob", 25})
people.Add(Person{"Charlie", 35})
// 检查集合
fmt.Println(people.Contains(Person{"Alice", 30})) // 输出: true
}
性能考虑
- 对于单线程应用,使用
NewSet()
创建的非线程安全集合性能更高 - 对于并发场景,使用
NewThreadSafeSet()
创建的线程安全集合
注意事项
- 该库要求 Go 1.18+ 版本
- 自定义类型作为集合元素时,必须实现可比较接口
- 集合会自动去重相同的元素
这个库已经被许多知名公司和项目使用,包括 Ethereum、Docker、1Password 和 Hashicorp 等。
更多关于golang高性能线程安全与非线程安全集合操作插件库golang-set的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高性能线程安全与非线程安全集合操作插件库golang-set的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang高性能集合操作库golang-set使用指南
golang-set是一个高性能的Golang集合操作库,提供了线程安全和非线程安全的实现,支持多种集合操作如并集、交集、差集等。
安装
go get github.com/deckarep/golang-set/v2
基本使用
创建集合
package main
import (
"fmt"
mapset "github.com/deckarep/golang-set/v2"
)
func main() {
// 创建线程安全的集合
safeSet := mapset.NewSet[int]()
// 创建非线程安全的集合
unsafeSet := mapset.NewThreadUnsafeSet[int]()
// 从切片创建集合
slice := []int{1, 2, 3}
setFromSlice := mapset.NewSetFromSlice(slice)
}
基本操作
// 添加元素
set.Add(1)
set.Add(2)
set.Add(3)
// 检查元素是否存在
if set.Contains(1) {
fmt.Println("Set contains 1")
}
// 移除元素
set.Remove(2)
// 获取集合大小
size := set.Cardinality()
fmt.Printf("Set size: %d\n", size)
// 清空集合
set.Clear()
集合运算
setA := mapset.NewSet[int](1, 2, 3, 4)
setB := mapset.NewSet[int](3, 4, 5, 6)
// 并集
union := setA.Union(setB)
fmt.Println("Union:", union) // 输出: Union: Set{1, 2, 3, 4, 5, 6}
// 交集
intersection := setA.Intersect(setB)
fmt.Println("Intersection:", intersection) // 输出: Intersection: Set{3, 4}
// 差集 (A有而B没有的)
difference := setA.Difference(setB)
fmt.Println("Difference:", difference) // 输出: Difference: Set{1, 2}
// 对称差集 (仅在A或仅在B中的元素)
symDifference := setA.SymmetricDifference(setB)
fmt.Println("Symmetric Difference:", symDifference) // 输出: Symmetric Difference: Set{1, 2, 5, 6}
集合关系判断
setX := mapset.NewSet[int](1, 2)
setY := mapset.NewSet[int](1, 2, 3)
// 判断是否为子集
isSubset := setX.IsSubset(setY) // true
fmt.Println("Is subset:", isSubset)
// 判断是否为真子集
isProperSubset := setX.IsProperSubset(setY) // true
fmt.Println("Is proper subset:", isProperSubset)
// 判断是否相等
isEqual := setX.Equal(mapset.NewSet[int](1, 2)) // true
fmt.Println("Is equal:", isEqual)
迭代集合
set := mapset.NewSet[string]("a", "b", "c")
// 使用迭代器
it := set.Iterator()
for elem := range it.C {
fmt.Println(elem)
}
// 直接遍历
for elem := range set.ToSlice() {
fmt.Println(elem)
}
线程安全与性能考虑
NewSet()
创建的是线程安全的集合,内部使用RWMutex保证并发安全NewThreadUnsafeSet()
创建非线程安全集合,性能更高但不支持并发访问
// 性能对比示例
func benchmarkSet(b *testing.B, set mapset.Set[int]) {
for i := 0; i < b.N; i++ {
set.Add(i)
set.Contains(i)
set.Remove(i)
}
}
func BenchmarkSafeSet(b *testing.B) {
set := mapset.NewSet[int]()
benchmarkSet(b, set)
}
func BenchmarkUnsafeSet(b *testing.B) {
set := mapset.NewThreadUnsafeSet[int]()
benchmarkSet(b, set)
}
实际应用示例
// 用户标签系统示例
type User struct {
ID int
Tags mapset.Set[string]
}
func NewUser(id int) *User {
return &User{
ID: id,
Tags: mapset.NewThreadUnsafeSet[string](), // 假设每个用户的tags独立操作
}
}
func main() {
user1 := NewUser(1)
user1.Tags.Add("vip")
user1.Tags.Add("premium")
user2 := NewUser(2)
user2.Tags.Add("vip")
// 找出共同标签
commonTags := user1.Tags.Intersect(user2.Tags)
fmt.Println("Common tags:", commonTags) // 输出: Common tags: Set{vip}
// 推荐标签 (用户1有而用户2没有的)
recommendTags := user1.Tags.Difference(user2.Tags)
fmt.Println("Recommend tags:", recommendTags) // 输出: Recommend tags: Set{premium}
}
golang-set库提供了丰富的集合操作方法,在需要高性能集合操作的场景下非常有用,特别是在处理大量数据时,选择线程安全或非线程安全版本可以根据具体场景获得最佳性能。