„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Warum führt das Erhöhen einer Variablen durch meine Goroutine zu unerwarteten Ergebnissen?

Warum führt das Erhöhen einer Variablen durch meine Goroutine zu unerwarteten Ergebnissen?

Veröffentlicht am 05.11.2024
Durchsuche:260

Why Does My Goroutine Incrementing a Variable Produce Unexpected Results?

Ist dies ein Ergebnis der Compiler-Optimierung?

In diesem Codeausschnitt wird eine Goroutine gestartet und erhöht wiederholt die Variable i:

package main

import "time"

func main() {
    i := 1
    go func() {
        for {
            i  
        }
    }()
    

Die Ausgabe ist jedoch immer 1. Dieses Verhalten kann dem Go-Speichermodell und der spezifischen Implementierung dieses Codes zugeschrieben werden.

Das Go-Speichermodell

Das Das Go-Speichermodell definiert die Bedingungen, unter denen garantiert werden kann, dass Lesevorgänge einer Variablen in einer Goroutine Werte beobachten, die durch Schreibvorgänge in dieselbe Variable in einer anderen Goroutine erzeugt werden. Es betont die Bedeutung der Synchronisierung für den gleichzeitigen Zugriff auf gemeinsam genutzte Daten.

Auslassen der Synchronisierung

Im angegebenen Code:

  • Die Zuweisung an i (d. h. i) Es folgt kein Synchronisierungsereignis, was darauf hinweist, dass Änderungen möglicherweise nicht sofort für andere Goroutinen sichtbar sind.
  • Der Compiler kann diese Schleifenoptimierung optimieren, indem er sie auf einen No-Op vereinfacht.

Optimierung durch den Compiler

Ein aggressiver Compiler könnte die i-Anweisung löschen und die Goroutine effektiv reduzieren auf:

for {}

Beispiel mit Synchronisierung

Um zu zeigen, dass das Problem auf die mangelnde Synchronisierung zurückzuführen ist, betrachten Sie den folgenden Code:

package main

import (
    "sync"
    "time"
)

func main() {
    mx := new(sync.Mutex)
    i := 1
    go func() {
        for {
            mx.Lock()
            i  
            mx.Unlock()
        }
    }()
    

In diesem Fall ist die Ausgabe nicht mehr 1, sondern wie erwartet eine große Zahl. Der sync.Mutex sorgt für Synchronisierung und stellt sicher, dass beide Goroutinen auf kontrollierte Weise auf i zugreifen, wodurch die Goroutine i inkrementieren kann und die Änderungen für die Hauptroutine sichtbar werden.

Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3