Maison >développement back-end >Golang >Comment résoudre les blocages Go causés par les opérations asynchrones et les canaux vides ?

Comment résoudre les blocages Go causés par les opérations asynchrones et les canaux vides ?

Barbara Streisand
Barbara Streisandoriginal
2024-12-11 18:04:12244parcourir

How to Resolve Go Deadlocks Caused by Asynchronous Operations and Empty Channels?

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!

Déclaration:
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