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. Есть ли в golang какой-либо тип, который можно использовать для одновременной записи с одинаковыми значениями? Мне нужно всегда использовать мьютекс или атомарную переменную?

-1
Junhee Woo 17 Май 2021 в 04:23

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()
}
5
wasmup 17 Май 2021 в 03:45