package main
import (
"container/list"
"fmt"
"sync"
"time"
)
/*
Author: Guo
Date: 3/15/21 4:58 PM
Description:
Company:
Updated: 姓名@时间@版本 变更说明
*/
// 限量器
type Limitor struct {
// 锁
Lock sync.Mutex
// 存储元素的双向链表
Elements *list.List
// 最多可以保存的元素个数
MaxNum int
// 时间窗口的长度
TimeWindow time.Duration
}
// 构造方法
func NewLimitor(maxNum int, timeW time.Duration) *Limitor {
return &Limitor{
//Lock: sync.Mutex{},
Elements: list.New(),
MaxNum: maxNum,
TimeWindow: timeW,
}
}
func IsFullOrAdd(limitor *Limitor, t time.Time) bool {
limitor.Lock.Lock()
defer limitor.Lock.Unlock()
// 如果没超过最大限度就存储
if limitor.Elements.Len() < limitor.MaxNum {
limitor.Elements.PushBack(t)
return false
} else {
// 否则就要删除老旧的元素
// 取出链表的头元素,也就是最早加入到链表的元素
tmp := limitor.Elements.Front()
for tmp != nil {
// 如果最早加入到链表的元素在时间窗口内,说明没有元素可以删除,已满
if time.Now().Add(-1 * limitor.TimeWindow).Before(tmp.Value.(time.Time)) {
return true
} else {
// 否则删除掉头元素
limitor.Elements.Remove(limitor.Elements.Front())
// 如果此时链表里有空间了,就加入
if limitor.Elements.Len() < limitor.MaxNum {
limitor.Elements.PushBack(t)
return false
}
// 否则头指针前移,再来一次
tmp = limitor.Elements.Front()
}
}
}
return true
}
func main() {
limitOr := NewLimitor(5, 10*time.Second)
for {
t := time.Now()
if IsFullOrAdd(limitOr, t) {
break
}
fmt.Println(t)
time.Sleep(time.Second)
}
time.Sleep(time.Second * 10)
if IsFullOrAdd(limitOr, time.Now()) {
fmt.Println("full")
} else {
fmt.Println("saved")
}
tmp := limitOr.Elements.Front()
for tmp != nil {
fmt.Println(tmp.Value.(time.Time))
limitOr.Elements.Remove(tmp)
tmp = limitOr.Elements.Front()
}
}
控制台输出结果:
2021-03-15 19:16:47.861605539 +0800 HKT m=+0.000073557
2021-03-15 19:16:48.861766058 +0800 HKT m=+1.000234300
2021-03-15 19:16:49.862036845 +0800 HKT m=+2.000505121
2021-03-15 19:16:50.862195606 +0800 HKT m=+3.000663861
2021-03-15 19:16:51.862422857 +0800 HKT m=+4.000891158
saved
2021-03-15 19:16:48.861766058 +0800 HKT m=+1.000234300
2021-03-15 19:16:49.862036845 +0800 HKT m=+2.000505121
2021-03-15 19:16:50.862195606 +0800 HKT m=+3.000663861
2021-03-15 19:16:51.862422857 +0800 HKT m=+4.000891158
2021-03-15 19:17:02.862979158 +0800 HKT m=+15.001447425
可以看到最早加入的元素被删除了。
这种情况下,在队列满了之后,队列里面始终会有五个元素。
还有另外一种实现方式:
package main
import (
"container/list"
"fmt"
"sync"
"time"
)
/*
Author: Guo
Date: 3/15/21 4:58 PM
Description:
Company:
Updated: 姓名@时间@版本 变更说明
*/
// 限量器
type Limitor struct {
// 锁
Lock sync.Mutex
// 存储元素的双向链表
Elements *list.List
// 最多可以保存的元素个数
MaxNum int
// 时间窗口的长度
TimeWindow time.Duration
}
// 构造方法
func NewLimitor(maxNum int, timeW time.Duration) *Limitor {
return &Limitor{
//Lock: sync.Mutex{},
Elements: list.New(),
MaxNum: maxNum,
TimeWindow: timeW,
}
}
func IsFullOrAdd(limitor *Limitor, t time.Time) bool {
limitor.Lock.Lock()
defer limitor.Lock.Unlock()
// 如果没超过最大限度就存储
if limitor.Elements.Len() < limitor.MaxNum {
limitor.Elements.PushBack(t)
return false
} else {
// 否则就要删除老旧的元素
// 取出链表的头元素,也就是最早加入到链表的元素
tmp := limitor.Elements.Front()
for tmp != nil {
// 如果最早加入到链表的元素在时间窗口内,说明没有元素可以删除,已满
if time.Now().Add(-1 * limitor.TimeWindow).Before(tmp.Value.(time.Time)) {
break
} else {
// 否则删除掉头元素
limitor.Elements.Remove(limitor.Elements.Front())
// 头指针前移,再来一次
tmp = limitor.Elements.Front()
}
}
// 如果此时链表里有空间了,就加入
if limitor.Elements.Len() < limitor.MaxNum {
limitor.Elements.PushBack(t)
return false
}
}
return true
}
func main() {
limitOr := NewLimitor(5, 10*time.Second)
for {
t := time.Now()
if IsFullOrAdd(limitOr, t) {
break
}
fmt.Println(t)
time.Sleep(time.Second)
}
time.Sleep(time.Second * 10)
if IsFullOrAdd(limitOr, time.Now()) {
fmt.Println("full")
} else {
fmt.Println("saved")
}
tmp := limitOr.Elements.Front()
for tmp != nil {
fmt.Println(tmp.Value.(time.Time))
limitOr.Elements.Remove(tmp)
tmp = limitOr.Elements.Front()
}
}
这时控制台输出结果:
2021-03-15 19:26:59.970839953 +0800 HKT m=+0.000070166
2021-03-15 19:27:00.971275169 +0800 HKT m=+1.000505762
2021-03-15 19:27:01.971694545 +0800 HKT m=+2.000924876
2021-03-15 19:27:02.971869634 +0800 HKT m=+3.001099985
2021-03-15 19:27:03.972041835 +0800 HKT m=+4.001272199
saved
2021-03-15 19:27:14.972562803 +0800 HKT m=+15.001793159
可以看到,这次队列里面所有超期的元素都被删除掉了。