Cet exemple d'utilisation est-il sync.WaitGroup
correct? Cela donne le résultat attendu, mais je ne suis pas sûr du wg.Add(4)
et de la position de wg.Done()
. Est-il judicieux d'ajouter les quatre goroutines à la fois avecwg.Add()
?
http://play.golang.org/p/ecvYHiie0P
package main
import (
"fmt"
"sync"
"time"
)
func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
duration := millisecs * time.Millisecond
time.Sleep(duration)
fmt.Println("Function in background, duration:", duration)
wg.Done()
}
func main() {
var wg sync.WaitGroup
wg.Add(4)
go dosomething(200, &wg)
go dosomething(400, &wg)
go dosomething(150, &wg)
go dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
Résultat (comme prévu):
Function in background, duration: 150ms
Function in background, duration: 200ms
Function in background, duration: 400ms
Function in background, duration: 600ms
Done
defer wg.Done()
appel au début de la fonction.Réponses:
Oui, cet exemple est correct. Il est important que le
wg.Add()
se produise avant lago
déclaration pour éviter les conditions de course. Ce qui suit serait également correct:Cependant, il est plutôt inutile d'appeler
wg.Add
encore et encore lorsque vous savez déjà combien de fois il sera appelé.Waitgroups
panique si le compteur tombe en dessous de zéro. Le compteur commence à zéro, chacunDone()
est un-1
et chacunAdd()
dépend du paramètre. Donc, pour s'assurer que le compteur ne tombe jamais en dessous et éviter les paniques, vous devezAdd()
être assuré de venir avant leDone()
.Dans Go, ces garanties sont données par le modèle de mémoire .
Le modèle de mémoire indique que toutes les instructions d'une même goroutine semblent être exécutées dans le même ordre qu'elles sont écrites. Il est possible qu'ils ne soient pas réellement dans cet ordre, mais le résultat sera comme si c'était le cas. Il est également garanti qu'un goroutine ne s'exécute qu'après l'
go
instruction qui l'appelle . Puisque leAdd()
se produit avant l'go
instruction et que l'go
instruction se produit avant leDone()
, nous connaissons leAdd()
se produit avant leDone()
.Si vous deviez faire passer l'
go
instruction avant leAdd()
, le programme peut fonctionner correctement. Cependant, ce serait une condition de course car elle ne serait pas garantie.la source
defer wg.Done()
pour être sûrs qu'il soit appelé quel que soit l'itinéraire emprunté par la goroutine? Merci.defer
et que l'un de vos goroutines ne parvient pas à appelerwg.Done()
... ne bloquerez-vous pas pourWait
toujours? On dirait que cela pourrait facilement introduire un bogue difficile à trouver dans votre code ...Je recommanderais d'intégrer l'
wg.Add()
appel dans ledoSomething()
fonction elle-même, de sorte que si vous ajustez le nombre de fois où il est appelé, vous n'ayez pas à ajuster séparément le paramètre d'ajout manuellement, ce qui pourrait entraîner une erreur si vous en mettez à jour un mais oubliez de mettre à jour le other (dans cet exemple trivial qui est peu probable, mais je crois personnellement que c'est une meilleure pratique pour la réutilisation du code).Comme le souligne Stephen Weinberg dans sa réponse à cette question , vous devez incrémenter le groupe d'attente avant de générer le gofunc, mais vous pouvez le faire facilement en enveloppant le spawn gofunc dans la
doSomething()
fonction elle-même, comme ceci:Ensuite, vous pouvez l'appeler sans l'
go
invocation, par exemple:Comme terrain de jeu: http://play.golang.org/p/WZcprjpHa_
la source
la source