Exemples détaillés de boucle for et de goroutine dans Golang

巴扎黑
Libérer: 2017-09-05 11:41:08
original
1906 Les gens l'ont consulté

Cet article vous présente principalement les informations pertinentes sur les problèmes de boucle for et de goroutine dans Golang. L'article les présente en détail à travers un exemple de code. Il a une certaine valeur d'apprentissage de référence pour que tous puissent apprendre ou utiliser Golang. Apprenons avec l'éditeur ci-dessous.

Contexte

Récemment, alors que j'étudiais le cours distribué 6.824 du MIT, j'ai rencontré quelques problèmes lors de l'utilisation de Go pour implémenter le protocole Raft. question. Je le partage pour référence et étude de tous. Je n’en dirai pas plus ci-dessous, jetons un coup d’œil à l’introduction détaillée.

Voir le code suivant :


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
    }
   }
  }()
}
Copier après la connexion

Parmi eux, la longueur de la tranche des pairs est de 3, donc la plus élevée l'indice est 2, la boucle for dans le code devrait être très intuitive dans la programmation non parallèle, et je n'avais pas réalisé qu'il y avait quelque chose qui n'allait pas à l'époque. Cependant, pendant le processus de débogage, des erreurs d'index hors limites ont continué à être signalées. Les informations de débogage montraient que la valeur de i était 3. À ce moment-là, je n'arrivais toujours pas à comprendre comment la condition de boucle pouvait devenir 3 alors qu'elle était clairement i <

Analyse

Bien que je ne comprenne pas ce qui s'est passé, je sais que cela devrait être causé par la goroutine introduite dans le boucle. Après Google, j'ai découvert qu'il y avait une page dans le wiki de Go intitulée Common Mistake - Using goroutines on loop iterator variables qui mentionne spécifiquement ce problème. Cela semble être très courant ~

Les débutants l'utilisent souvent. Utilisez le code suivant pour traiter les données en parallèle :


for val := range values {
 go val.MyMethod()
}
Copier après la connexion

ou utilisez la fermeture :


for val := range values {
 go func() {
  fmt.Println(val)
 }()
}
Copier après la connexion

Le problème ici est que val est en fait une variable unique qui parcourt toutes les données de la tranche. Puisque la fermeture n'est liée qu'à cette variable val, il est très probable que le résultat du code ci-dessus soit que toutes les goroutines génèrent le dernier élément de la tranche. En effet, il est très probable que la goroutine ne commencera à s'exécuter qu'après l'exécution de la boucle for, et à ce moment-là, la valeur de val pointe vers le dernier élément de la tranche.


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.
Copier après la connexion

Solution

La bonne façon d'écrire le code ci-dessus est :


for val := range values {
 go func(val interface{}) {
  fmt.Println(val)
 }(val)
}
Copier après la connexion

Ici, val est transmis à la goroutine en tant que paramètre. Chaque val sera calculée indépendamment et enregistrée dans la pile de la goroutine, obtenant ainsi les résultats attendus.

Une autre méthode consiste à définir de nouvelles variables dans la boucle. Étant donné que les variables définies dans la boucle ne sont pas partagées lors du parcours de la boucle, le même effet peut être obtenu :


<🎜. >

for i := range valslice {
 val := valslice[i]
 go func() {
  fmt.Println(val)
 }()
}
Copier après la connexion
Pour le problème mentionné au début de l'article, la solution la plus simple est d'ajouter une variable temporaire dans la boucle et de remplacer tous les i dans la goroutine suivante par cette variable temporaire, c'est-à-dire Disponible :


server := i
Copier après la connexion

Résumé

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal