AtomicStoreUint32 vs. Zuweisung in Sync.Once
Beim Untersuchen des Quellcodes für den sync.Once-Typ von Go taucht eine Frage bezüglich der Verwendung auf von atomic.StoreUint32 im Vergleich zu einer regulären Zuweisung zum Setzen des Fertig-Flags.
Falsche Implementierung:
Der ursprüngliche Quellcode enthielt eine falsche Implementierung:
<code class="go">func (o *Once) Do(f func()) { if atomic.CompareAndSwapUint32(&o.done, 0, 1) { f() } }</code>
Diese Implementierung kann nicht garantieren, dass f vollständig ist, wenn die Funktion zurückkehrt. Gleichzeitige Anrufe könnten dazu führen, dass der Gewinner f ausführt, während der zweite Anrufer sofort zurückkehrt, vorausgesetzt, der erste Anruf ist abgeschlossen, was möglicherweise nicht der Fall ist.
Korrekte Implementierung:
Um dieses Problem zu beheben, verwendet die aktuelle Implementierung atomic.StoreUint32 in Verbindung mit einem Mutex:
<code class="go">func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 0 { o.doSlow(f) } }</code>
<code class="go">func (o *Once) doSlow(f func()) { o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(&o.done, 1) f() } }</code>
Warum AtomicStoreUint32?
Die Verwendung von atomic .StoreUint32 ist notwendig, um sicherzustellen, dass andere Goroutinen die Änderung an o.done beobachten können, nachdem f abgeschlossen ist. Während primitive Zuweisungen auf bestimmten Architekturen atomar sein können, erfordert das Speichermodell von Go die Verwendung des Atompakets, um atomare Operationen über alle unterstützten Architekturen hinweg zu gewährleisten.
Zugriff auf Fertig-Flag:
Das Ziel besteht darin, sicherzustellen, dass der Zugriff auf das Fertig-Flag außerhalb des Mutex sicher ist. Daher werden atomare Operationen anstelle der Sperrung mit einem Mutex verwendet. Diese Optimierung erhöht die Effizienz des Fast Path und ermöglicht den Einsatz von sync.Once in Szenarien mit hohem Datenverkehr.
Mutex für doSlow:
Der Mutex in doSlow sorgt dafür dass nur ein Aufrufer f ausführt, bevor o.done gesetzt wird. atomic.StoreUint32 wird zum Schreiben des Flags verwendet, da es gleichzeitig mit atomic.LoadUint32 außerhalb des kritischen Abschnitts des Mutex auftreten kann.
Gleichzeitige Schreib- und Lesevorgänge:
Direktes Lesen o.done in doSlow ist aufgrund des Mutex-Schutzes sicher. Darüber hinaus ist das gleichzeitige Lesen von o.done mit atomic.LoadUint32 sicher, da beide Vorgänge nur das Lesen beinhalten.
Das obige ist der detaillierte Inhalt vonWarum verwendet „sync.Once' „atomic.StoreUint32' anstelle einer regulären Zuweisung für das Flag „done'?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!