Maison  >  Article  >  développement back-end  >  Comment éviter les impasses dans Go Goroutines lorsque les producteurs sont de courte durée ?

Comment éviter les impasses dans Go Goroutines lorsque les producteurs sont de courte durée ?

Linda Hamilton
Linda Hamiltonoriginal
2024-10-25 07:09:02784parcourir

How to Avoid Deadlock in Go Goroutines When Producers Are Short-Lived?

Résoudre les blocages dans les goroutines Go

Dans la programmation simultanée, un blocage se produit lorsque plusieurs goroutines s'attendent indéfiniment pour terminer les opérations, interrompant ainsi le processus. programme. Cet article traite d'un blocage spécifique rencontré dans la simultanéité Go, comme décrit dans la question d'origine :

<code class="go">package main

import (
    "fmt"
    "time"
)

func producer(ch chan int, d time.Duration, num int) {
    for i := 0; i < num; i++ {
        ch <- i
        time.Sleep(d)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch, 100*time.Millisecond, 2)
    go producer(ch, 200*time.Millisecond, 5)
    for {
        fmt.Println(<-ch)
    }
    close(ch)
}</code>

Ce code déclenche une erreur de blocage en raison des facteurs suivants :

  • Les producteurs , qui envoient des valeurs au canal, sont de courte durée et finissent par cesser de produire des données.
  • La boucle for sans fin dans la fonction principale reçoit en continu des valeurs du canal sans condition de terminaison.
  • Le Le canal est fermé après la boucle sans fin, ce qui fait qu'aucune autre valeur n'est disponible pour la réception.

Solution : résiliation coordonnée

Pour éviter une impasse, les producteurs doivent être coordonné pour signaler l'achèvement, et la chaîne doit être fermée par le dernier producteur. Voici une solution efficace utilisant un sync.WaitGroup pour la coordination :

<code class="go">func producer(ch chan int, d time.Duration, num int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < num; i++ {
        ch <- i
        time.Sleep(d)
    }
}

func main() {
    wg := &sync.WaitGroup{}
    ch := make(chan int)

    wg.Add(1)
    go producer(ch, 100*time.Millisecond, 2, wg)
    wg.Add(1)
    go producer(ch, 200*time.Millisecond, 5, wg)

    go func() {
        wg.Wait()
        close(ch)
    }()

    for v := range ch {
        fmt.Println(v)
    }
}</code>

Dans cette solution :

  • On incrémente le WaitGroup pour chaque producteur.
  • Chaque producteur décrémente le WaitGroup une fois terminé via une instruction defer.
  • Une goroutine attend que le WaitGroup atteigne zéro (ce qui signifie que tous les producteurs ont terminé) et ferme le canal.
  • La boucle principale utilise une plage for construire pour parcourir les valeurs envoyées sur le canal avant sa fermeture.

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