Go 不可重复协程安全队列
代码实现
package dataStruct
import (
"errors"
"sync"
)
// GenericQueue 是一个支持泛型的不可重复队列,具有最大长度限制
// T 是泛型参数
type GenericQueue[T comparable] struct {
items map[T]struct{} // 使用 map 来存储元素
order []T // 使用切片来记录元素的顺序
lock sync.RWMutex // 读写锁,保证并发安全
maxSize int // 最大队列长度
}
// NewGenericQueue 创建一个新的泛型队列,并指定最大长度
func NewGenericQueue[T comparable](maxSize int) *GenericQueue[T] {
return &GenericQueue[T]{
items: make(map[T]struct{}), // 初始化 items map
order: []T{}, // 初始化 order 切片
maxSize: maxSize, // 设置最大长度
}
}
// Add 添加元素到队列
// 如果队列已满,默认移除最旧的元素来腾出空间
func (q *GenericQueue[T]) Add(item T) error {
q.lock.Lock() // 加写锁,防止并发修改
defer q.lock.Unlock() // 解锁
// 判断元素是否已经存在
if _, exists := q.items[item]; exists {
return errors.New("item already exists in the queue")
}
// 如果队列已满,移除最旧的元素
if len(q.order) >= q.maxSize {
return errors.New("Out of length Queue ")
}
// 将元素添加到 map 中,标记该元素已存在
q.items[item] = struct{}{}
// 将元素添加到队列顺序中
q.order = append(q.order, item)
return nil
}
// Remove 删除队列中的指定元素
// 如果元素不存在,则返回错误
func (q *GenericQueue[T]) Remove(item T) error {
q.lock.Lock() // 加写锁,防止并发修改
defer q.lock.Unlock() // 解锁
// 判断元素是否存在
if _, exists := q.items[item]; !exists {
return errors.New("item not found in the queue")
}
// 从 map 中删除该元素
delete(q.items, item)
// 从顺序切片中删除该元素
for i, v := range q.order {
if v == item {
q.order = append(q.order[:i], q.order[i+1:]...) // 删除指定位置的元素
break
}
}
return nil
}
// Update 修改队列中的元素
// 如果元素不存在,则返回错误
func (q *GenericQueue[T]) Update(oldItem, newItem T) error {
q.lock.Lock() // 加写锁,防止并发修改
defer q.lock.Unlock() // 解锁
// 判断 oldItem 是否存在
if _, exists := q.items[oldItem]; !exists {
return errors.New("old item not found in the queue")
}
// 判断 newItem 是否已存在
if _, exists := q.items[newItem]; exists {
return errors.New("new item already exists in the queue")
}
// 从 map 中删除 oldItem,并添加 newItem
delete(q.items, oldItem)
q.items[newItem] = struct{}{}
// 更新顺序切片中的 oldItem 为 newItem
for i, v := range q.order {
if v == oldItem {
q.order[i] = newItem
break
}
}
return nil
}
// Contains 查询队列中是否存在指定元素
func (q *GenericQueue[T]) Contains(item T) bool {
q.lock.RLock() // 加读锁,防止并发修改
defer q.lock.RUnlock() // 解锁
_, exists := q.items[item]
return exists
}
// Traverse 遍历队列中的元素
func (q *GenericQueue[T]) Traverse() []T {
q.lock.RLock() // 加读锁,防止并发修改
defer q.lock.RUnlock() // 解锁
// 返回元素的副本,防止并发问题
result := make([]T, len(q.order))
copy(result, q.order)
return result
}
// Iterator 返回一个可以用于 for range 的通道
func (q *GenericQueue[T]) Iterator() <-chan T {
ch := make(chan T)
go func() {
q.lock.RLock() // 加读锁,防止并发修改
defer q.lock.RUnlock() // 解锁
defer close(ch) // 关闭通道
for _, item := range q.order {
ch <- item
}
}()
return ch
}
介绍
1. 支持泛型
- 队列支持泛型参数
T
,因此可以存储任何类型的元素,只要该类型是comparable
(可比较的)。这意味着你可以使用这个队列来存储数字、字符串、结构体等类型的数据。
2. 不可重复
- 队列内部通过
map
来存储元素,因此它自动确保元素的唯一性。也就是说,队列中不会有重复的元素。
3. 顺序存储
- 使用切片
order
来记录元素的顺序,保证在遍历时元素的顺序是加入队列时的顺序。
4. 并发安全
- 队列实现了并发控制,使用了
sync.RWMutex
读写锁来保证在多线程环境下的安全操作。多个 goroutine 可以并发地读取队列,或者一个 goroutine 可以安全地修改队列。
5. 常见操作
- 添加元素(Add): 如果元素已经存在,则无法再次添加;如果队列已满,返回
Out of length Queue
错误,不会自动移除最旧元素 - 删除元素(Remove): 可以删除队列中的某个元素。
- 更新元素(Update): 可以将队列中的某个元素更新为新的元素,前提是新元素不存在。
- 检查元素是否存在(Contains): 查询队列中是否包含某个元素。
- 遍历队列(Traverse): 返回队列中所有元素的副本,供遍历使用。
- 支持
for range
遍历: 通过Iterator
方法,队列可以返回一个只读通道,可以直接在for range
循环中使用。
6. 适用场景
- 适用于需要按顺序处理且确保元素唯一的场景,例如任务队列、事件队列等。
- 适用于并发环境,确保多个操作的安全性。
示例用法:
type Ta struct {
Name string
}
func main() {
impl := test.XueTestingImpl
impl.StartTest()
// 示例:创建一个支持整数的泛型队列
queue := dataStruct.NewGenericQueue[Ta](1024)
queue.Add(Ta{Name: "xzm"})
queue.Add(Ta{Name: "yyds"})
queue.Add(Ta{Name: "id"})
//修改
queue.Update(Ta{Name: "id"}, Ta{Name: "ids"})
//遍历
for ta := range queue.Iterator() {
fmt.Println(ta)
}
//查找
contains := queue.Contains(Ta{
Name: "yyds",
})
//删除
queue.Remove(Ta{
Name: "yyds",
})
fmt.Println(contains)
fmt.Println(queue)
fmt.Println(queue.Traverse())
impl.EndTest()
}
原文地址:https://blog.csdn.net/qq_52160611/article/details/145330782
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!