Sync.Once реализация - PullRequest
       11

Sync.Once реализация

0 голосов
/ 03 июня 2019

У меня вопрос по поводу sync.Once () в Go 1.12. Исходный код ниже:

// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.

func (o *Once) Do(f func()) {
    if atomic.LoadUint32(&o.done) == 1 {
        return
    }
    // Slow-path.
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}

Почему бы просто не использовать переменную uint32, а затем выполнить CAS для этой переменной. Это кажется более эффективным и не приведет к тупику.

Код как:

type Once uint32
func (o *Once) Do(f func()) {
    if atomic.CompareAndSwapUint32((*uint32)(o), 0, 1) {
        f()
    }
}

1 Ответ

10 голосов
/ 03 июня 2019

Once.Do() не возвращается, пока f() не будет выполнен один раз.Это означает, что если несколько программ вызовут Once.Do() одновременно, f() будет выполнен один раз, но все вызовы будут ждать до завершения f() (они будут заблокированы).

Ваше предлагаемое решение не имеетэто очень важное свойство!Вы только гарантируете, что f() будет выполнен только один раз, но при одновременном вызове из нескольких программ последующие вызовы будут немедленно возвращены, даже если f() все еще выполняется.

Когда мы используем sync.Once, мыполагаться на это поведение, мы полагаемся на то, что f() завершается после вызова Once.Do(), поэтому мы можем использовать все переменные, которые f() инициализированы безопасно, без условия гонки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...