我正在實現一個集成第三方 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 關注
- 156 瀏覽
添加回答
舉報
0/150
提交
取消