| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- package maps
- import "sync/atomic"
- type (
- OrderedMap[K comparable, V any] struct {
- batchLoop int // 批量处理循环次数
- writeChan chan any // 写入缓冲区
- stopChan chan struct{} // 停止信号
- closed int32 // 原子关闭标记
- }
- queueCmdSet[K comparable, V any] struct {
- key K
- value V
- }
- queueCmdPop[K comparable, V any] struct {
- limit int
- result chan []V
- }
- queueCmdLen struct {
- result chan int
- }
- // internal data structure
- // orderQueue 封装了有序队列的底层实现,包含 Map 和 Slice 的管理
- orderQueue[K comparable, V any] struct {
- pairs map[K]V // 所有数据
- keys []K // 所有key(保证先进先出)
- head int // 记录当前有效数据的起始索引
- }
- )
- func newOrderQueue[K comparable, V any]() *orderQueue[K, V] {
- return &orderQueue[K, V]{
- pairs: make(map[K]V),
- keys: make([]K, 0, 1024),
- head: 0,
- }
- }
- func (q *orderQueue[K, V]) set(key K, value V) {
- if _, found := q.pairs[key]; found {
- q.pairs[key] = value
- } else {
- q.keys = append(q.keys, key)
- q.pairs[key] = value
- }
- }
- func (q *orderQueue[K, V]) pop(limit int) []V {
- total := len(q.keys) - q.head
- if total <= 0 {
- return nil
- }
- batchSize := limit
- if batchSize > total {
- batchSize = total
- }
- if batchSize <= 0 {
- return nil
- }
- result := make([]V, 0, batchSize)
- for i := 0; i < batchSize; i++ {
- k := q.keys[q.head]
- v := q.pairs[k]
- result = append(result, v)
- delete(q.pairs, k)
- var zero K
- q.keys[q.head] = zero // free reference
- q.head++
- }
- // incremental compaction
- if q.head > 1024 && q.head > len(q.keys)/2 {
- newKeys := make([]K, len(q.keys)-q.head)
- copy(newKeys, q.keys[q.head:])
- q.keys = newKeys
- q.head = 0
- }
- return result
- }
- func (q *orderQueue[K, V]) len() int {
- return len(q.pairs)
- }
- func NewOrderMap[K comparable, V any](chanSize, batchLoop int) *OrderedMap[K, V] {
- if chanSize <= 0 {
- chanSize = 10000
- }
- if batchLoop <= 0 {
- batchLoop = 10
- }
- om := &OrderedMap[K, V]{
- batchLoop: batchLoop,
- writeChan: make(chan any, chanSize),
- stopChan: make(chan struct{}),
- }
- go om.loop()
- return om
- }
- func (om *OrderedMap[K, V]) loop() {
- queue := newOrderQueue[K, V]()
- // processCmd 处理单个命令
- processCmd := func(cmd any) {
- switch c := cmd.(type) {
- case *queueCmdSet[K, V]:
- queue.set(c.key, c.value)
- case *queueCmdPop[K, V]:
- c.result <- queue.pop(c.limit)
- case *queueCmdLen:
- c.result <- queue.len()
- }
- }
- for {
- // 1. 阻塞等待:如果没有任务,在这里让出 CPU
- select {
- case <-om.stopChan:
- return
- case cmd := <-om.writeChan:
- // 收到第一个任务,立即处理
- processCmd(cmd)
- }
- // 2. 批量消费:唤醒后,贪婪地消费所有积压任务
- // 设置一个最大批量限制,防止单个协程长期霸占 CPU
- BatchLoop:
- for i := 0; i < om.batchLoop; i++ {
- select {
- case cmd := <-om.writeChan:
- processCmd(cmd)
- case <-om.stopChan:
- return
- default:
- // Channel 空了,回到外层阻塞
- break BatchLoop
- }
- }
- }
- }
- func (om *OrderedMap[K, V]) isClosed() bool {
- return atomic.LoadInt32(&om.closed) == 1
- }
- // Set 是异步的 (fire and forget)
- func (om *OrderedMap[K, V]) Set(key K, value V) {
- if om.isClosed() {
- return
- }
- // 直接发送,如果满则阻塞(背压)
- om.writeChan <- &queueCmdSet[K, V]{key: key, value: value}
- }
- func (om *OrderedMap[K, V]) Len() int {
- if om.isClosed() {
- return 0
- }
- resultChan := make(chan int, 1)
- om.writeChan <- &queueCmdLen{result: resultChan}
- return <-resultChan
- }
- // PopBatch 高效批量弹出
- func (om *OrderedMap[K, V]) PopBatch(limit int) []V {
- if limit <= 0 || om.isClosed() {
- return nil
- }
- resultChan := make(chan []V, 1)
- om.writeChan <- &queueCmdPop[K, V]{limit: limit, result: resultChan}
- return <-resultChan
- }
- func (om *OrderedMap[K, V]) Pop() (V, bool) {
- batch := om.PopBatch(1)
- if len(batch) > 0 {
- return batch[0], true
- }
- var zero V
- return zero, false
- }
- func (om *OrderedMap[K, V]) Close() {
- if !atomic.CompareAndSwapInt32(&om.closed, 0, 1) {
- return
- }
- close(om.stopChan)
- }
- func (om *OrderedMap[K, V]) GetStopChan() <-chan struct{} {
- return om.stopChan
- }
|