为了账号安全,请及时绑定邮箱和手机立即绑定

想要数据竞争还是糟糕的设计?

想要数据竞争还是糟糕的设计?

Go
慕姐8265434 2023-08-14 17:02:35
我正在实现一个集成第三方 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()


查看完整回答
反对 回复 2023-08-14
  • 1 回答
  • 0 关注
  • 71 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信