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库提供了丰富的集合操作方法,在需要高性能集合操作的场景下非常有用,特别是在处理大量数据时,选择线程安全或非线程安全版本可以根据具体场景获得最佳性能。

回到顶部