我正在实现一个集成第三方 API 的应用程序,该 API 每秒的点击次数有限制。我编写了我的适配器,直到我使用竞争条件检测器运行测试之前,我是一个快乐的人。设计很简单,有一个:计算其发出的请求的结构每秒将此计数器重置为 0 的刻度该结构上的私有函数将被阻塞,直到满足条件以允许对 API 进行额外的调用。运行此测试用例效果非常好,直到您给它-race标记为止。我相信数据争用是由滴答线程试图重置命中计数器和增加它的调用请求引起的......我的设计是否糟糕,或者我应该忍受数据争用警报吗?import ( "sync" "testing" "time")var subject httpClientWrapperfunc 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.Mutexfunc (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") }}
1 回答
PIPIONE
TA贡献1829条经验 获得超9个赞
任何对互斥体的访问都.hits应该在互斥体后面,所以
// reset hits every second to 0
go func() {
tick := time.Tick(1 * time.Second)
for range tick {
m.Lock()
subject.hits = 0
m.Unlock()
}
}()
此外,互斥体锁定时不应发生任何睡眠,因此
m.Lock()
...
{
m.Unlock()
// cool down for one second
time.Sleep(1 * time.Second)
m.Lock()
...
}
...
m.Unlock()
- 1 回答
- 0 关注
- 114 浏览
添加回答
举报
0/150
提交
取消