priorityqueue

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2024 License: MPL-2.0 Imports: 4 Imported by: 0

README

使用小/大顶堆实现的无锁化优先级队列

这是一个使用Go语言实现的通用优先级队列库,支持小顶堆和大顶堆两种模式。该库基于Go的container/heap包,提供了一种高效的方式来管理和操作具有优先级的元素。

特性

  • 支持泛型,允许使用任意可比较类型作为元素值和优先级
  • 提供小顶堆和大顶堆两种模式
  • 无锁化设计,使用CAS原子操作实现并发安全,提高了并发性能
  • 高效的堆操作,时间复杂度为O(log n)
  • 支持更新元素的优先级
  • 提供了清空优先级队列的方法

安装

使用Go模块管理依赖,添加以下内容到你的go.mod文件:

import "github.com/ycvk/priority-queue"

然后运行go mod tidy下载依赖。

使用方法

创建优先级队列
pq := New[int, int](MinHeap) // 创建一个小顶堆
pq := New[string, float64](MaxHeap) // 创建一个大顶堆
添加元素
pq.Put(10, 5)
pq.Put(20, 3)
pq.Put(30, 7)
获取元素
item := pq.Get() // 获取优先级最高的元素,但不移除
item = pq.GetAndPop() // 获取并移除优先级最高的元素
更新元素的优先级
pq.Update(20, 8) // 更新元素20的优先级为8
更新或插入元素
pq.Upsert("abc", 11) // 更新或者插入元素abc的优先级为11
清空优先级队列
pq.Clear()

示例

package main

import (
    "fmt"
    pq "github.com/ycvk/priority-queue"
)

func main() {
    mpq := pq.New[string, int](pq.MinHeap)

    mpq.Put("task1", 5)
    mpq.Put("task2", 3)
    mpq.Put("task3", 7)

    fmt.Println(mpq.GetAndPop()) // 输出:&{task2 3}
    fmt.Println(mpq.GetAndPop()) // 输出:&{task1 5}

    mpq.Update("task3", 1)

    fmt.Println(mpq.GetAndPop()) // 输出:&{task3 1}
}

无锁化设计

本库采用无锁化设计,使用CAS(Compare-And-Swap)原子操作来实现并发安全。相比传统的互斥锁,无锁化设计可以显著提高并发性能,减少线程阻塞和上下文切换的开销。

在无锁化实现中,我使用unsafe.Pointer和原子操作来管理共享资源,如切片和映射。通过原子地加载和存储指针,保证了并发访问的安全性。

同时,我优化了一些关键操作,如PushPop,通过直接操作切片指针来避免不必要的内存分配和复制。在Update操作中,只有当元素的优先级实际发生变化时,才触发堆调整,减少了冗余操作。

这些优化和无锁化设计使得本库在高并发场景下表现出色,同时保证了数据的正确性和一致性。

Benchmark

使用mutex加锁方式时(代码详见v1_mutex目录下):

goos: darwin
goarch: arm64
pkg: github.com/ycvk/priority-queue
BenchmarkHeapPriorityQueue
BenchmarkHeapPriorityQueue/Put
BenchmarkHeapPriorityQueue/Put-10         	 2501148	       589.9 ns/op
BenchmarkHeapPriorityQueue/Get
BenchmarkHeapPriorityQueue/Get-10         	48504936	        24.67 ns/op
BenchmarkHeapPriorityQueue/GetAndPop
BenchmarkHeapPriorityQueue/GetAndPop-10   	  253447	      4601 ns/op
BenchmarkHeapPriorityQueue/Update
BenchmarkHeapPriorityQueue/Update-10      	  423760	      2821 ns/op
PASS
Exiting.

使用目前CAS原子化操作时:

goos: darwin
goarch: arm64
pkg: github.com/ycvk/priority-queue
BenchmarkHeapPriorityQueue
BenchmarkHeapPriorityQueue/Put
BenchmarkHeapPriorityQueue/Put-10         	 4053801	       369.4 ns/op
BenchmarkHeapPriorityQueue/Get
BenchmarkHeapPriorityQueue/Get-10         	582441570	         2.057 ns/op
BenchmarkHeapPriorityQueue/GetAndPop
BenchmarkHeapPriorityQueue/GetAndPop-10   	  354594	      2124 ns/op
BenchmarkHeapPriorityQueue/Update
BenchmarkHeapPriorityQueue/Update-10      	 1000000	      1045 ns/op
PASS

可以看到快了几倍以上。

许可证

本项目采用许可证详情请参阅LICENSE文件。

贡献

欢迎提交问题和合并请求。如果你发现任何bug或有任何改进建议,请随时提出。我们非常重视性能和并发安全,如果你有任何优化思路或发现潜在的并发问题,也欢迎与我们分享。

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type HeapPriorityQueue

type HeapPriorityQueue[T comparable, P constraints.Ordered] struct {
	// contains filtered or unexported fields
}

HeapPriorityQueue 基于容器/堆的优先级队列实现

func (*HeapPriorityQueue[T, P]) BatchPut

func (pq *HeapPriorityQueue[T, P]) BatchPut(items ...*Item[T, P])

BatchPut 批量将元素添加到优先级队列中

func (*HeapPriorityQueue[T, P]) Clear

func (pq *HeapPriorityQueue[T, P]) Clear()

Clear 清空优先级队列

func (*HeapPriorityQueue[T, P]) Get

func (pq *HeapPriorityQueue[T, P]) Get() *Item[T, P]

Get 返回优先级队列中的下一个元素而不移除它

func (*HeapPriorityQueue[T, P]) GetAndPop

func (pq *HeapPriorityQueue[T, P]) GetAndPop() *Item[T, P]

GetAndPop 移除并返回优先级队列中的下一个元素

func (*HeapPriorityQueue[T, P]) IsEmpty

func (pq *HeapPriorityQueue[T, P]) IsEmpty() bool

IsEmpty 检查优先级队列是否为空

func (*HeapPriorityQueue[T, P]) Len

func (pq *HeapPriorityQueue[T, P]) Len() int

Len implements heap.Interface

func (*HeapPriorityQueue[T, P]) Less

func (pq *HeapPriorityQueue[T, P]) Less(i, j int) bool

Less implements heap.Interface

func (*HeapPriorityQueue[T, P]) Pop

func (pq *HeapPriorityQueue[T, P]) Pop() any

Pop implements heap.Interface 弹出最后一个元素

func (*HeapPriorityQueue[T, P]) Push

func (pq *HeapPriorityQueue[T, P]) Push(x any)

Push implements heap.Interface

func (*HeapPriorityQueue[T, P]) Put

func (pq *HeapPriorityQueue[T, P]) Put(value T, priority P)

Put 将元素添加到优先级队列中

func (*HeapPriorityQueue[T, P]) Swap

func (pq *HeapPriorityQueue[T, P]) Swap(i, j int)

Swap implements heap.Interface

func (*HeapPriorityQueue[T, P]) Update

func (pq *HeapPriorityQueue[T, P]) Update(value T, priority P)

Update 更新元素的优先级

func (*HeapPriorityQueue[T, P]) Upsert added in v0.1.2

func (pq *HeapPriorityQueue[T, P]) Upsert(value T, priority P)

Upsert 插入新元素或更新已有元素的优先级

type HeapType

type HeapType int

HeapType 指定堆类型 - 最小或最大

const (
	MinHeap HeapType = iota // 小顶堆
	MaxHeap                 // 大顶堆
)

type Item

type Item[T any, P constraints.Ordered] struct {
	Value    T // 元素值
	Priority P // 元素优先级
}

Item 代表优先级队列中的一个元素

type PriorityQueue

type PriorityQueue[T any, P constraints.Ordered] interface {
	Len() int
	Put(value T, priority P)
	BatchPut(items ...*Item[T, P])
	Get() *Item[T, P]
	GetAndPop() *Item[T, P]
	IsEmpty() bool
	Update(value T, priority P)
	Upsert(value T, priority P)
	Clear()
}

func New

func New[T comparable, P constraints.Ordered](kind HeapType) PriorityQueue[T, P]

New 创建一个新的优先级队列

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL