赞
踩
package main import ( "fmt" "sync" "time" ) // 令牌桶结构体 type TokenBucket struct { tokens chan struct{} rate time.Duration // 桶容量 limit int } // 创建令牌桶 func NewTokenBucket(rate time.Duration, limit int) *TokenBucket { return &TokenBucket{ tokens: make(chan struct{}, limit), rate: rate, limit: limit, } } // 放入令牌 func (t *TokenBucket) AddToken() { select { case t.tokens <- struct{}{}: { fmt.Println("放入成功") } default: // 桶已满,丢弃令牌 fmt.Println("桶已满,丢弃令牌") } } // 取出令牌 func (t *TokenBucket) GetToken() bool { select { case <-t.tokens: return true case <-time.After(t.rate): // fmt.Println("获取失败") return false } } func main() { // 创建令牌桶,每秒放入 10 个令牌,桶容量为 10 tb := NewTokenBucket(time.Second, 5) var success = make(chan struct{}, 3000) var fail = make(chan struct{}, 3000) var total = make(chan struct{}, 3000) var x int var wg sync.WaitGroup wg.Add(1) go func() { defer func() { wg.Done() }() for i := 0; i < 11; i++ { // fmt.Println("尝试放入") tb.AddToken() time.Sleep(time.Millisecond * 500) tb.AddToken() time.Sleep(time.Millisecond * 500) } }() wg.Add(1) go func() { defer func() { wg.Done() }() for k := 0; k < 10; k++ { for j := 0; j < 100; j++ { wg.Add(1) go func(k, j int) { defer func() { wg.Done() total <- struct{}{} }() token := tb.GetToken() x++ if token { success <- struct{}{} fmt.Printf("\033[32m请求通过![%d,%d]\033[0m\n", k, j) } else { fail <- struct{}{} fmt.Printf("\033[31m请求被拒绝![%d,%d]\033[0m\n", k, j) } }(k, j) } time.Sleep(time.Second) } }() wg.Wait() fmt.Printf("成功: %d, 失败: %d,总数:%d\n", len(success), len(fail), len(total)) fmt.Println("end", x) }
我在进行测试的时候,一开始success和fail这两个变量使用的是切片,我在多次运行后发现,succsss+fail并不等于total,但是打印的执行流程是没有问题的,于是想到切片是存在数据并发安全问题的,改为channel才得到了正确的结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。