【发布时间】:2019-12-30 04:30:21
【问题描述】:
我正在实现一个集成第三方 API 的应用,该 API 具有每秒点击次数限制。我编写了我的适配器,在我使用竞争条件检测器运行测试之前,我是一个快乐的人。
设计简单,有一个:
- 计算其发出的请求的结构
- 每秒将此计数器重置为 0 的滴答声
- 此结构上的私有函数在满足允许对 API 进行额外调用之前一直阻塞。
在你给它-race 标志之前,运行这个测试用例效果很好。
我相信数据竞争是由试图重置命中计数器的滴答线程和增加它的调用请求引起的......
我的设计是坏的还是我应该忍受数据竞争警报?
import (
"sync"
"testing"
"time"
)
var subject httpClientWrapper
func init() {
subject = httpClientWrapper{
hits: 0,
hitsSecond: 1,
}
// reset hits every second to 0
go func() {
tick := time.Tick(1 * time.Second)
for range tick {
subject.hits = 0
}
}()
}
type httpClientWrapper struct {
hits, hitsSecond int
}
var m sync.Mutex
func (c *httpClientWrapper) allowCall() {
m.Lock()
callAllowanceReached := c.hits >= c.hitsSecond
for callAllowanceReached {
// cool down for one second
time.Sleep(1 * time.Second)
callAllowanceReached = c.hits >= c.hitsSecond
}
c.hits = c.hits + 1
m.Unlock()
}
func TestItSleeps(t *testing.T) {
timeStart := time.Now()
var wg = sync.WaitGroup{}
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
subject.allowCall()
wg.Done()
}()
}
wg.Wait()
elapsedTime := time.Since(timeStart)
if elapsedTime < (1 * time.Second) {
t.Errorf("this test should not had been able to run in less than a second due to locks and cool down")
}
}
【问题讨论】:
-
永远不要仅仅“忍受”竞争条件。