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

可以看到,这次队列里面所有超期的元素都被删除掉了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值