跳至主要內容

Go 实现队列

Mayee...大约 1 分钟

需求

用 Go 实现一个固定大小的队列结构,当队列中进入新数据时判断,如果超过限制则淘汰最早的数据,使队列大小始终不超过最大限制。

1. 实现

缓存代码queue.go

package queue

import (
    "go.uber.org/zap"
	"math"
	"time"
)

type queue []time.Time

var GlobalReqLimit = queue{}

// 最大 5 个元素
const maxSize = 5

//加入元素
//这里需要使用指针
func (q *queue) Push(v time.Time) {
	// 队列是否已满
	if q.IsFull() {
		// 对比第一个时间,如果在 1 分钟内则等待
		first := q.Offer()
		sub := int(math.Ceil(time.Now().UTC().Sub(first).Seconds()))
		for sub <= 60 {
			logger.Info("request rate limit, wait a moment", zap.Int("second", 60-sub))
			time.Sleep(time.Second)
			sub = int(math.Ceil(time.Now().UTC().Sub(first).Seconds()))
		}
		q.Pop()
	}
	*q = append(*q, v)
}

// 弹出第一个元素
func (q *queue) Pop() time.Time {
	head := (*q)[0]
	*q = (*q)[1:]
	return head
}

// 查看第一个元素,但不弹出
func (q *queue) Offer() time.Time {
	return (*q)[0]
}

//判断是否为空
func (q *queue) IsEmpty() bool {
	return q.Size() == 0
}

//判断是否已满
func (q *queue) IsFull() bool {
	return q.Size() == maxSize
}

func (q *queue) Size() int {
	return len(*q)
}

测试queue_test.go

package queue

import (
	"testing"
	"time"
)

func TestQueue(t *testing.T) {
	GlobalReqLimit.Push(time.Now().UTC())
	println(GlobalReqLimit.Size())
	GlobalReqLimit.Offer()
	println(GlobalReqLimit.Size())
}

测试结果:

=== RUN   TestQueue
1
1
--- PASS: TestQueue (0.00s)
PASS