標籤:傳值 輸出 代碼 解決方案 怎麼 需求 ++ 條件 3.4
在之前的go語言的速率限制這篇文章裡,我們嘗試了普通的速率限制,和脈衝型速率限制。其中,脈衝型速率限制是放開了限制,裡面有3個請求是一次性到達,然後再按照200ms的速度限制的,之前的代碼如下所示:
package mainimport "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 {<-limiterfmt.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 {<-burstyLimiterfmt.Println("request", req, time.Now())}}
最終的輸出是下面這樣,可以看到下面那段輸出的前三次輸出,時間幾乎沒差,這是一次脈衝型速率限制:
request 1 2018-04-17 12:57:02.823975218 +0800 CST m=+0.205374957request 2 2018-04-17 12:57:03.024067833 +0800 CST m=+0.405476106request 3 2018-04-17 12:57:03.220187209 +0800 CST m=+0.601603847request 4 2018-04-17 12:57:03.420175881 +0800 CST m=+0.801601050request 5 2018-04-17 12:57:03.622105704 +0800 CST m=+1.003539485request 1 2018-04-17 12:57:03.622191244 +0800 CST m=+1.003625029request 2 2018-04-17 12:57:03.622210962 +0800 CST m=+1.003644748request 3 2018-04-17 12:57:03.622223153 +0800 CST m=+1.003656939request 4 2018-04-17 12:57:03.82356235 +0800 CST m=+1.205004724request 5 2018-04-17 12:57:04.024178896 +0800 CST m=+1.405629826
那我們如果想實現另一種脈衝型速率限制怎麼辦,就是一開始,讓速度變慢,然後再正常請求的,經過思考,代碼改造如下:
package mainimport "fmt"import "time"func main() {k := 0requests := 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 {<-slowk++}<-limiterfmt.Println("request", req, time.Now())}}
運行結果如下,可以看到,前三次間隔是400ms,第四次又還原回來間隔200ms:
request 1 2018-04-17 17:04:50.9986303 +0800 CST m=+0.405591505request 2 2018-04-17 17:04:51.395919457 +0800 CST m=+0.802875205request 3 2018-04-17 17:04:51.794626945 +0800 CST m=+1.201577217request 4 2018-04-17 17:04:51.993709916 +0800 CST m=+1.400657453request 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語言中速率限制的思考