1. 程式人生 > >005_針對於go語言中速率限制的思考

005_針對於go語言中速率限制的思考

回來 條件 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語言中速率限制的思考