Heim > Backend-Entwicklung > Golang > Warum verwendet „sync.Once' „atomic.StoreUint32' anstelle einer regulären Zuweisung für das Flag „done'?

Warum verwendet „sync.Once' „atomic.StoreUint32' anstelle einer regulären Zuweisung für das Flag „done'?

Barbara Streisand
Freigeben: 2024-10-31 05:40:01
Original
771 Leute haben es durchsucht

Why does `sync.Once` use `atomic.StoreUint32` instead of a regular assignment for the `done` flag?

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>
Nach dem Login kopieren

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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren

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!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage