Liegt das daran, dass der go-Compiler den Code optimiert hat?

8
%Vor%

Die Ausgabe ist immer 1 .

Allerdings ist es absolut ausreichend, dass 1s genug ist, damit die for -Schleife viele Male durchlaufen kann.

Ich denke, die i in der Schließung ist die i in der main func.

Siehe den folgenden Code.

%Vor%

Nach vielen Zeilen von "+1" ist die Ausgabe genau wie erwartet eine große Zahl.

    
lucky yang 12.11.2017, 01:37
quelle

2 Antworten

11
  

Das Go-Speichermodell

     

Version vom 31. Mai 2014

     

Einführung

     

Das Go-Speichermodell gibt die Bedingungen an, unter denen a   Variable in einer Goroutine kann garantiert werden, produzierte Werte zu beobachten   durch schreibt auf die gleiche Variable in einer anderen Goroutine.

     

Hinweis

     

Programme, die Daten modifizieren, auf die gleichzeitig mehrfach zugegriffen wird   Göroutinen müssen diesen Zugang serialisieren.

     

Um den Zugriff zu serialisieren, schützen Sie die Daten mit Kanaloperationen oder anderem   Synchronization Primitive wie diejenigen in der Synchronisation und Sync / atomaren   Pakete.

     

Wenn Sie den Rest dieses Dokuments lesen müssen, um das Verhalten zu verstehen   von deinem Programm bist du zu schlau.

     

Sei nicht schlau.

     

Synchronisation

%Vor%      

Auf die Zuweisung zu a folgt kein Synchronisationsereignis   es ist nicht garantiert, dass es von einer anderen Goroutine beobachtet wird. Eigentlich,   Ein aggressiver Compiler könnte die gesamte go-Anweisung löschen.

Der Zuweisung an i , über inkrement i++ ( i = i + 1 ), folgt kein Synchronisierungsereignis, sodass nicht garantiert ist, dass es von einer anderen Goroutine beobachtet wird. In der Tat könnte ein aggressiver Compiler die gesamte i++ -Anweisung löschen.

Zum Beispiel

%Vor%

Ausgabe:

%Vor%

Die Goroutine reduziert sich auf:

%Vor%

Für den Compiler

%Vor%

kann implementiert werden, indem ein Register für immer inkrementiert wird, im Wesentlichen eine no-op for -Schleife.

%Vor%

Nach dem Einfügen einer print -Anweisung,

%Vor%

Ausgabe:

%Vor%

Die Goroutine erweitert sich zu

%Vor%

Die erhöhte Komplexität der Goroutine bedeutet, dass der Compiler nicht länger daran denkt, ein Register dem Wert von i zu widmen. Der In-Memory-Wert von i wird erhöht, wodurch die Aktualisierungen mit einem Datenrennen für die main -Goroutine sichtbar werden.

%Vor%

Fügen Sie für das erwartete Ergebnis eine Synchronisierung hinzu,

%Vor%

Ausgabe:

%Vor%     
peterSO 12.11.2017, 05:27
quelle
1

Der gleichzeitige Zugriff auf die Variable i muss synchronisiert werden:

  

Synchronisation ist besser mit Kanälen oder den Einrichtungen der   Paket synchronisieren Speicher teilen durch Kommunikation; kommuniziere nicht mit   Speicher teilen.

Hinweis: Ссылка

Das ist interessant, also teile ich meine Experimente:

0- Ihr Code mit time.Sleep(1 * time.Second) ( nicht empfohlen - nicht synchronisiert ):

%Vor%

Ausgabe:

%Vor%

1- Verwendung von i := new(int) ( nicht empfohlen - nicht synchronisiert ):

%Vor%

Ausgabe (CPU: i7-7700K @ 4,2 GHz):

%Vor%

2- Synchronisieren mit atomic.AddInt64(&i, 1) ( Paket atomic bietet grundlegende atomare Speichergrundelemente niedriger Ebene, die für die Implementierung von Synchronisationsalgorithmen nützlich sind ):

%Vor%

Ausgabe:

%Vor%

3- Synchronisieren mit chan int :

%Vor%

Ausgabe:

%Vor%

4- Synchronisation mit sync.WaitGroup :

%Vor%

Ausgabe:

%Vor%

5- Synchronisieren mit quit-Kanal:

%Vor%

Ausgabe:

%Vor%

6- Synchronisation mit sync.RWMutex :

%Vor%

Ausgabe:

%Vor%

verwandte Themen:

Das Go-Speichermodell
Es gibt keine Entsprechung zu volatilen und registrieren in Go
Unterstützt Go volatile / nichtflüchtige Variablen?

    
A.R 12.11.2017 07:03
quelle

Tags und Links