Ограничаването на скоростта на обработка на входящите данни1 е важно за управлението на използваните ресурси и поддръжка на качеството на доставяните услуги. Го подхожда изкусно чрез съвместна употреба на канали, гозадачи и часовници.
import (
"fmt"
"time"
)
func main() {
Първо ще разгледаме най-простия начин за ограничаване на скоростта. Да предположим, че искаме да ограничим обработката на входящите заявки. Ще обслужваме тези заявки по канал със същото име.
заявки := make(chan int, 5)
for i := 1; i <= 5; i++ {
заявки <- i
}
close(заявки)
Каналът ограничител ще произвежда по една
стойност на всеки 200 милисекунди. Това е
регулаторът в нашето устройство за ограничаване на
скоростта.
ограничител := time.Tick(200 * time.Millisecond)
Програмата спира хода си, защото чака стойност от
канала часовник ограничител. Така ограничаваме
програмата да обработва най-много една заявка от
канала заявки на всеки 200 милисекунди.
for req := range заявки {
време := <-ограничител
fmt.Println("заявка",
req, време.Format(`15:04.000`))
}
Може да искаме да разрешим кратки резки покачвания
на броя на заявките, като същевременно поддържаме
цялостното ограничение. Можем да постигнем това,
като задържаме данни в канала ограничител.
Каналът разрешаващСкок ще позволява скокове
до три събития.
разрешаващСкок := make(chan time.Time, 3)
Да напълним канала за скок на заявките.
for range 3 {
разрешаващСкок <- time.Now()
}
На всеки 200 милисекунди ще добавяме нова стойност
в разрешаващСкок, докато достигнем ограничението
3.
go func() {
for t := range time.Tick(200 * time.Millisecond) {
разрешаващСкок <- t
}
}()
Сега наподобяваме още 5 новопристигащи заявки. Три
от тях ще се възползват от възможността за скок в
обработката на заявките, разрешен от
ограничителНаСкока.
скочилиЗаявки := make(chan int, 5)
for i := 1; i <= 5; i++ {
скочилиЗаявки <- i
}
close(скочилиЗаявки)
for req := range скочилиЗаявки {
t := <-разрешаващСкок
fmt.Println("заявки",
req, t.Format(`15:04.000`))
}
}
Като пуснем програмата виждаме, че заявките от първата поредица биват обработени по една на 200 милисекунди, както искахме.
$ go run rate-limiting.go
заявка 1 10:35.357
заявка 2 10:35.557
заявка 3 10:35.757
заявка 4 10:35.957
заявка 5 10:35.157
При втората поредица от заявки, обслужваме първите три незабавно, понеже сме разрешили скок на ставката. Следващите две обработваме със забавяне от по 200 милисекунди за всяка.
заявки 1 10:35.158
заявки 2 10:35.158
заявки 3 10:35.158
заявки 4 10:35.358
заявки 5 10:35.558
Следващ пример: Неделими броячи.