Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Beispiele für For-Schleife und Goroutine in Golang

Detaillierte Beispiele für For-Schleife und Goroutine in Golang

巴扎黑
巴扎黑Original
2017-09-05 11:41:081810Durchsuche

Dieser Artikel führt Sie hauptsächlich in die relevanten Informationen zu For-Loop- und Goroutine-Problemen ein. Der Artikel stellt ihn anhand von Beispielcodes ausführlich vor. Er bietet einen gewissen Referenz-Lernwert für alle, die Golang benötigen Lass es uns mit dem untenstehenden Editor lernen.

Hintergrund

Vor Kurzem stieß ich beim Studium des verteilten Kurses 6.824 des MIT auf einige Probleme bei der Verwendung von Go zur Implementierung des Raft-Protokolls. Frage. Ich teile es zum Nachschlagen und Studieren für alle. Ich werde im Folgenden nicht viel sagen, werfen wir einen Blick auf die detaillierte Einführung.

Siehe den folgenden Code:


for i := 0; i < len(rf.peers); i++ {
  DPrintf("i = %d", i)

  if i == rf.me {
   DPrintf("skipping myself #%d", rf.me)
   continue
  }

  go func() {
   DPrintf("len of rf.peers = %d", len(rf.peers))
   DPrintf("server #%d sending request vote to server %d", rf.me, i)
   reply := &RequestVoteReply{}
   ok := rf.sendRequestVote(i, args, reply)
   if ok && reply.VoteGranted && reply.Term == rf.currentTerm {
    rf.voteCount++
    if rf.voteCount > len(rf.peers)/2 {
     rf.winElectionCh <- true
    }
   }
  }()
}

Unter diesen beträgt die Länge des Peers-Slices 3, also die höchste Der Index ist 2. Die for-Schleife im Code sollte in der nichtparallelen Programmierung sehr intuitiv sein, und ich wusste zu diesem Zeitpunkt nicht, dass daran etwas nicht stimmte. Während des Debugging-Vorgangs wurden jedoch immer wieder Indexfehler außerhalb der Grenzen gemeldet. Die Debugging-Informationen zeigten, dass der Wert von i 3 war. Zu diesem Zeitpunkt konnte ich immer noch nicht herausfinden, wie die Schleifenbedingung 3 werden konnte, obwohl i <

Analyse

Obwohl ich nicht verstehe, was passiert ist, weiß ich, dass es durch die im eingeführte Goroutine verursacht werden sollte Schleife. Nach Google habe ich herausgefunden, dass es im Go-Wiki eine Seite mit dem Titel „Common Mistake – Goroutines on Loop Iterator Variables“ gibt, die dieses Problem ausdrücklich erwähnt. Ich lache so sehr ~

Anfänger verwenden es oft Verwenden Sie den folgenden Code, um Daten parallel zu verarbeiten:


for val := range values {
 go val.MyMethod()
}

oder verwenden Sie den Abschluss:


for val := range values {
 go func() {
  fmt.Println(val)
 }()
}

Das Problem hierbei ist, dass val tatsächlich eine einzelne Variable ist, die alle Daten im Slice durchläuft. Da der Abschluss nur an diese Val-Variable gebunden ist, ist es sehr wahrscheinlich, dass das Ergebnis des obigen Codes darin besteht, dass alle Goroutinen das letzte Element des Slice ausgeben. Dies liegt daran, dass die Goroutine höchstwahrscheinlich erst dann mit der Ausführung beginnt, wenn die for-Schleife ausgeführt wird und der Wert von val zu diesem Zeitpunkt auf das letzte Element im Slice zeigt.


The val variable in the above loops is actually a single variable that takes on the value of each slice element. Because the closures are all only bound to that one variable, there is a very good chance that when you run this code you will see the last element printed for every iteration instead of each value in sequence, because the goroutines will probably not begin executing until after the loop.

Lösung

Die richtige Art, den obigen Code zu schreiben, ist:


for val := range values {
 go func(val interface{}) {
  fmt.Println(val)
 }(val)
}

Hier wird der Wert als Parameter an die Goroutine übergeben. Jeder Wert wird unabhängig berechnet und im Stapel der Goroutine gespeichert, wodurch die erwarteten Ergebnisse erzielt werden.

Eine andere Methode besteht darin, neue Variablen innerhalb der Schleife zu definieren. Da die innerhalb der Schleife definierten Variablen während des Schleifendurchlaufs nicht gemeinsam genutzt werden, kann der gleiche Effekt erzielt werden:


for i := range valslice {
 val := valslice[i]
 go func() {
  fmt.Println(val)
 }()
}

Für das am Anfang des Artikels erwähnte Problem besteht die einfachste Lösung darin, eine temporäre Variable in der Schleife hinzuzufügen und alle i in der nachfolgenden Goroutine durch diese temporäre Variable zu ersetzen, das heißt Verfügbar:


server := i

Zusammenfassung

Das obige ist der detaillierte Inhalt vonDetaillierte Beispiele für For-Schleife und Goroutine in Golang. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
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