【问题标题】:golang concurrent write to uint64 variable with same values?golang并发写入具有相同值的uint64变量?
【发布时间】:2021-05-17 01:23:57
【问题描述】:
type simpleTx struct {
    gas uint64
}

func (tx *simpleTx) UpdateGas() {
    tx.gas = 125
}

func TestUpdateGas(t *testing.T) {
    var wg sync.WaitGroup
    wg.Add(100)

    tx := &simpleTx{}
    for i:=0; i <100; i++ {
        go func(t *simpleTx)() {
            tx.UpdateGas()
            wg.Done()
        }(tx)
    }

    wg.Wait()
}

使用-race 选项运行时,上述测试会打印出“WARNING:DATA RACE”。 golang 中是否有任何类型可用于具有相同值的并发写入? 我需要始终使用互斥锁或原子变量吗?

【问题讨论】:

  • golang 中是否有任何类型可以用于并发写入相同的值? 没有。我需要始终使用互斥锁或原子变量吗? i> 是的。
  • 并发写入相同的值是未定义的行为。了解sync.Once 可能会有所帮助,它允许您多次调用同一个函数,但只执行一次。

标签: go concurrency


【解决方案1】:

是的,有很多 Go 习惯用法 - 以防止数据竞争 - 不应该在没有适当同步的情况下并发写入变量(或并发读写):

  1. 对于您的特殊情况 - 写入相同的值。使用sync.Once
type simpleTx struct {
    sync.Once
    gas uint64
}
func (tx *simpleTx) UpdateGas() {
    tx.Do(func() { tx.gas = 125 })
}
  1. 使用atomic.StoreUint64 进行原子写入:
atomic.StoreUint64(&tx.gas, 125)
  1. 使用sync.Mutex:
type simpleTx struct {
    sync.Mutex
    gas uint64
}

func (tx *simpleTx) UpdateGas() {
    tx.Lock()
    tx.gas = 125
    tx.Unlock()
}
  1. 使用频道:
type simpleTx struct {
    gas chan uint64
}
func (tx *simpleTx) UpdateGas() {
    select {
    case tx.gas <- 125:
    default:
    }
}
func TestUpdateGas(t *testing.T) {
    var wg sync.WaitGroup
    tx := &simpleTx{make(chan uint64, 1)}
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func(t *simpleTx) {
            tx.UpdateGas()
            wg.Done()
        }(tx)
    }
    wg.Wait()
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    • 2016-09-28
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多