Maison >développement back-end >Golang >Comment résoudre les blocages Go causés par les opérations asynchrones et les canaux vides ?
Deadlock in Go : "toutes les routines Go sont endormies"
Lors de l'exécution du code fourni, une impasse se produit en raison de son modèle d'exécution asynchrone en utilisant des goroutines. Le problème survient lorsque la fonction UnloadTrucks est appelée avant que des camions n'aient été envoyés vers le canal. Cela conduit le canal à rester vide, provoquant le blocage des goroutines de l'expéditeur sur la ligne ch <- tr. Étant donné que les goroutines de l'expéditeur attendent d'envoyer des camions, elles ne peuvent pas fermer le canal et la fonction UnloadTrucks, qui attend de recevoir des camions, est bloquée indéfiniment.
Solution : Utiliser WaitGroup pour fermer le canal
Pour résoudre l'impasse, nous pouvons fermer le canal ch une fois que toutes les goroutines ont fini d'envoyer des camions. Ceci peut être réalisé en introduisant un WaitGroup, une primitive de synchronisation qui suit le nombre de goroutines en attente :
go func() { wg.Wait() close(ch) }()
Cette goroutine attend que toutes les autres goroutines aient terminé leurs tâches (signalées par l'appel Wait()) avant fermer la chaîne. Ce faisant, la fonction UnloadTrucks est capable de se terminer normalement lorsque tous les camions ont été envoyés.
Code révisé :
package main import ( "fmt" "sync" "time" ) type Item struct { name string } type Truck struct { Cargo []Item name string } func UnloadTrucks(c chan Truck) { for t := range c { fmt.Printf("%s has %d items in cargo: %s\n", t.name, len(t.Cargo), t.Cargo[0].name) } } func main() { trucks := make([]Truck, 2) ch := make(chan Truck) var wg sync.WaitGroup for i, _ := range trucks { trucks[i].name = fmt.Sprintf("Truck %d", i+1) fmt.Printf("Building %s\n", trucks[i].name) } for t := range trucks { go func(tr Truck) { itm := Item{} itm.name = "Groceries" fmt.Printf("Loading %s\n", tr.name) tr.Cargo = append(tr.Cargo, itm) ch <- tr wg.Done() }(trucks[t]) wg.Add(1) } time.Sleep(50 * time.Millisecond) fmt.Println("Unloading Trucks") UnloadTrucks(ch) fmt.Println("Done") }
Avec ce code modifié, l'impasse est éliminé car la fonction UnloadTrucks est garantie de recevoir tous les camions avant la fermeture du canal. Cela garantit que toutes les goroutines accomplissent correctement leurs tâches et que le programme s'exécute sans aucune interruption inattendue.
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!