Lors de la programmation simultanée, nous rencontrons souvent des situations où nous devons attendre que toutes les goroutines soient terminées avant de poursuivre l'exécution. En langage Go, nous pouvons atteindre cet objectif en utilisant WaitGroup. WaitGroup est un sémaphore de comptage qui peut être utilisé pour attendre la fin d'un groupe de goroutines. Avant de continuer, nous devons appeler la méthode Wait de WaitGroup pour nous assurer que toutes les goroutines ont terminé leurs tâches. Dans cet article, nous présenterons comment utiliser correctement WaitGroup pour gérer l'ordre d'exécution des goroutines.
J'ai besoin du planificateur Golang pour exécuter toutes les goroutines avant de continuer, runtime.gosched() ne peut pas le résoudre.
Le problème est que la routine go s'exécute si vite que le "select" dans start() s'exécute après le "select" dans stopstream() puis "case <-chanstopstream:" le destinataire n'est pas prêt pour l'expéditeur "case retchan <-true :". Il s'avère que lorsque cela se produit, le résultat est le même comportement que lorsque stopstream() se bloque
Exécutez ce code https://go.dev/play/p/dq85xqju2q_z Plusieurs fois, vous verrez ces deux réponses Réponse attendue lorsqu'il n'est pas suspendu :
2009/11/10 23:00:00 start 2009/11/10 23:00:00 receive chan 2009/11/10 23:00:03 end
Réponse attendue en cas de suspension, mais pas si rapide en cas de suspension :
2009/11/10 23:00:00 start 2009/11/10 23:00:00 default 2009/11/10 23:00:01 timer 2009/11/10 23:00:04 end
Code
package main import ( "log" "runtime" "sync" "time" ) var wg sync.WaitGroup func main() { wg.Add(1) //run multiples routines on a huge system go start() wg.Wait() } func start() { log.Println("Start") chanStopStream := make(chan bool) go stopStream(chanStopStream) select { case <-chanStopStream: log.Println("receive chan") case <-time.After(time.Second): //if stopStream hangs do not wait more than 1 second log.Println("TIMER") //call some crash alert } time.Sleep(3 * time.Second) log.Println("end") wg.Done() } func stopStream(retChan chan bool) { //do some work that can be faster then caller or not runtime.Gosched() //time.Sleep(time.Microsecond) //better solution then runtime.Gosched() //time.Sleep(2 * time.Second) //simulate when this routine hangs more than 1 second select { case retChan <- true: default: //select/default is used because if the caller times out this routine will hangs forever log.Println("default") } }
Il n'y a aucun moyen d'exécuter toutes les autres goroutines avant de continuer l'exécution de la goroutine actuelle.
Correction du problème en s'assurant que la goroutine ne se bloque pas stopstream
:
Option 1 : Remplacez chanstopstream
par canal tamponné chanstopstream
更改为缓冲通道。这确保了 stopstream
. Cela garantit que
func start() { log.println("start") chanstopstream := make(chan bool, 1) // <--- buffered channel go stopstream(chanstopstream) ... } func stopstream(retchan chan bool) { ... // always send. no select/default needed. retchan <- true }
Option 2
: Fermez le canal au lieu d'envoyer la valeur. Les chaînes peuvent toujours être fermées par l'expéditeur. Reçoit une valeur zéro sur un canal fermé qui renvoie le type de valeur du canal.
func start() { log.Println("Start") chanStopStream := make(chan bool) // buffered channel not required go stopStream(chanStopStream) ... func stopStream(retChan chan bool) { ... close(retChan) }
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!