我一直试图为我的应用程序设置一个速率限制器并遇到了这段代码。阅读之后,我仍然无法理解它究竟做了什么。
我目前的理解:
1)调用SetSmallRateLimit和SetLongRateLimit来初始化通道并开始在goroutine中运行处理程序。
2)当调用requestAndUnmarshal时,checkRateLimiter会向队列通道发送信号。
我不明白:
1)RateLimitHandler在一段时间内休眠。在(pertime)之后,然后清除队列通道。不确定triggerWatcher和returnChan正在做什么。
2)checkTimeTrigger - 不要理解这个函数正在做什么或它的目的。
var (
smallRateChan rateChan
longRateChan rateChan
)
type rateChan struct {
RateQueue chan bool
TriggerChan chan bool
}
//10 requests every 10 seconds
func SetSmallRateLimit(numrequests int, pertime time.Duration) {
smallRateChan = rateChan{
RateQueue: make(chan bool, numrequests),
TriggerChan: make(chan bool),
}
go rateLimitHandler(smallRateChan, pertime)
}
//500 requests every 10 minutes
func SetLongRateLimit(numrequests int, pertime time.Duration) {
longRateChan = rateChan{
RateQueue: make(chan bool, numrequests),
TriggerChan: make(chan bool),
}
go rateLimitHandler(longRateChan, pertime)
}
func rateLimitHandler(RateChan rateChan, pertime time.Duration) {
returnChan := make(chan bool)
go timeTriggerWatcher(RateChan.TriggerChan, returnChan)
for {
<-returnChan
<-time.After(pertime)
go timeTriggerWatcher(RateChan.TriggerChan, returnChan)
length := len(RateChan.RateQueue)
for i := 0; i < length; i++ {
<-RateChan.RateQueue
}
}
}
func timeTriggerWatcher(timeTrigger chan bool, returnChan chan bool) {
timeTrigger <- true
returnChan <- true
}
func requestAndUnmarshal(requestURL string, v interface{}) (err error) {
checkRateLimiter(smallRateChan)
checkRateLimiter(longRateChan)
resp, err := http.Get(requestURL)
defer resp.Body.Close()
if err != nil {
return
}
checkTimeTrigger(smallRateChan)
checkTimeTrigger(longRateChan)
if resp.StatusCode != http.StatusOK {
return RiotError{StatusCode: resp.StatusCode}
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
err = json.Unmarshal(body, v)
if err != nil {
return
}
return
}
func checkRateLimiter(RateChan rateChan) {
if RateChan.RateQueue != nil && RateChan.TriggerChan != nil {
RateChan.RateQueue <- true
}
}
func checkTimeTrigger(RateChan rateChan) {
if RateChan.RateQueue != nil && RateChan.TriggerChan != nil {
select {
case <-RateChan.TriggerChan:
default:
}
}
}
答案 0 :(得分:1)
我认为您不应该使用此代码来学习任何有用的东西。 我不确定但它似乎试图限制请求率,但这是错误的。它允许发出一定数量的请求,然后等待一段时间。在时间间隔之后,它允许您再次发出请求。所有这一切都以非常复杂的方式完成。
但它可能导致非常奇怪的情况。假设你做1req / h,你的限制是500req / 20sec。然后,此代码将使您在500小时后等待20秒,并允许再次发出请求。
checkTimeTrigger
从RateChan.TriggerChan中删除一条消息,如果它有任何消息,如果没有,则不执行任何操作,并立即返回。
此代码显然不是DRY。更好地使用https://godoc.org/golang.org/x/time/rate,您希望限制请求率。