golang:时间窗口法实现限流器
Posted IGuoSJ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang:时间窗口法实现限流器相关的知识,希望对你有一定的参考价值。
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
可以看到,这次队列里面所有超期的元素都被删除掉了。
以上是关于golang:时间窗口法实现限流器的主要内容,如果未能解决你的问题,请参考以下文章