005_針對於go語言中速率限制的思考
阿新 • • 發佈:2018-04-17
回來 條件 chan 針對 完成 結果 int ++ if條件
在之前的go語言的速率限制這篇文章裏,我們嘗試了普通的速率限制,和脈沖型速率限制。其中,脈沖型速率限制是放開了限制,裏面有3個請求是一次性到達,然後再按照200ms的速度限制的,之前的代碼如下所示:
package main import "fmt" import "time" func main() { requests := make(chan int, 5) for i := 1; i <= 5; i++ { requests <- i } close(requests) limiter := time.Tick(time.Millisecond * 200) for req := range requests { <-limiter fmt.Println("request", req, time.Now()) } burstyLimiter := make(chan time.Time, 3) for i := 0; i < 3; i++ { burstyLimiter <- time.Now() } go func() { for t := range time.Tick(time.Millisecond * 200) { burstyLimiter <- t } }() burstyRequests := make(chan int, 5) for i := 1; i <= 5; i++ { burstyRequests <- i } close(burstyRequests) for req := range burstyRequests { <-burstyLimiter fmt.Println("request", req, time.Now()) } }
最終的輸出是下面這樣,可以看到下面那段輸出的前三次輸出,時間幾乎沒差,這是一次脈沖型速率限制:
request 1 2018-04-17 12:57:02.823975218 +0800 CST m=+0.205374957 request 2 2018-04-17 12:57:03.024067833 +0800 CST m=+0.405476106 request 3 2018-04-17 12:57:03.220187209 +0800 CST m=+0.601603847 request 4 2018-04-17 12:57:03.420175881 +0800 CST m=+0.801601050 request 5 2018-04-17 12:57:03.622105704 +0800 CST m=+1.003539485 request 1 2018-04-17 12:57:03.622191244 +0800 CST m=+1.003625029 request 2 2018-04-17 12:57:03.622210962 +0800 CST m=+1.003644748 request 3 2018-04-17 12:57:03.622223153 +0800 CST m=+1.003656939 request 4 2018-04-17 12:57:03.82356235 +0800 CST m=+1.205004724 request 5 2018-04-17 12:57:04.024178896 +0800 CST m=+1.405629826
那我們如果想實現另一種脈沖型速率限制怎麽辦,就是一開始,讓速度變慢,然後再正常請求的,經過思考,代碼改造如下:
package main import "fmt" import "time" func main() { k := 0 requests := make(chan int, 5) for i := 1; i <= 5; i++ { requests <- i } close(requests) limiter := time.Tick(time.Millisecond * 200) slow := time.Tick(time.Millisecond * 400) for req := range requests { if k < 3 { <-slow k++ } <-limiter fmt.Println("request", req, time.Now()) } }
運行結果如下,可以看到,前三次間隔是400ms,第四次又還原回來間隔200ms:
request 1 2018-04-17 17:04:50.9986303 +0800 CST m=+0.405591505 request 2 2018-04-17 17:04:51.395919457 +0800 CST m=+0.802875205 request 3 2018-04-17 17:04:51.794626945 +0800 CST m=+1.201577217 request 4 2018-04-17 17:04:51.993709916 +0800 CST m=+1.400657453 request 5 2018-04-17 17:04:52.196450634 +0800 CST m=+1.603395386
我來解釋下代碼邏輯。為了實現需求,我在前面又設置了一個打點器,然後增加判斷,如果k小於3,就從打點器中取值,然後k自增。這樣的話保證了前三次取值慢,後面的取值快。
這時候有人會問了,那例子中是總共兩個打點器,一個是400ms,一個是200ms,為什麽前三次不是400+200總共600ms,而是間隔只有400ms呢?
我來解釋一下,因為代碼運行到<-slow時候是阻塞狀態,通道內沒有值,是需要打點器每隔400ms把值存入slow中,才能繼續運行的。而<-limiter按理說也是阻塞狀態,也需要打點器傳值的。但是別忘了,limiter是200ms,在slow傳值之前,limiter就已經存入值了。所以在if判斷語句結束以後,limiter不用等待傳值,直接取就行了。這樣的話,在if條件執行完後,<-limiter執行是瞬間完成的,不用等待200ms的。
以上就是go語言中速率限制的一些思考和改造,在實際工作中,應該還有更加完美的解決方案,期待將來的改進。
005_針對於go語言中速率限制的思考