Maison  >  Article  >  développement back-end  >  Quelles sont les causes des blocages dans le code Go utilisant les WaitGroups et les Buffered Channels ?

Quelles sont les causes des blocages dans le code Go utilisant les WaitGroups et les Buffered Channels ?

PHPz
PHPzavant
2024-02-09 11:09:30701parcourir

使用 WaitGroups 和 Buffered Channels 的 Go 代码中出现死锁的原因是什么?

L'éditeur php Baicao répondra à une question courante dans cet article : "Quelle est la raison du blocage dans le code Go à l'aide des WaitGroups et des Buffered Channels ?" Dans le langage Go, les WaitGroups et les Buffered Channels sont des outils de programmation simultanés couramment utilisés. Cependant, vous pouvez parfois rencontrer des situations de blocage dans le code qui les utilise. Cet article examinera les causes des blocages et proposera des solutions pour aider les lecteurs à éviter ce problème. Que vous soyez débutant ou développeur Go expérimenté, cet article vous apportera de précieuses informations.

Contenu des questions

Groupes d'attente, canaux tampons et blocages

Ce code provoque une impasse, mais je ne sais pas pourquoi. J'ai essayé d'utiliser des mutex à plusieurs endroits différents, en fermant des canaux à l'intérieur et à l'extérieur de routines go distinctes, mais toujours le même résultat.

J'essaie d'envoyer des données via un canal (inputchan), puis de lire les données d'un autre canal (outputchan)

package main

import (
    "fmt"
    "sync"
)

func listStuff(wg *sync.WaitGroup, workerID int, inputChan chan int, outputChan chan int) {
    defer wg.Done()

    for i := range inputChan {
        fmt.Println("sending ", i)
        outputChan <- i
    }
}

func List(workers int) ([]int, error) {
    _output := make([]int, 0)

    inputChan := make(chan int, 1000)
    outputChan := make(chan int, 1000)

    var wg sync.WaitGroup
    wg.Add(workers)

    fmt.Printf("+++ Spinning up %v workers\n", workers)
    for i := 0; i < workers; i++ {
        go listStuff(&wg, i, inputChan, outputChan)
    }

    for i := 0; i < 3000; i++ {
        inputChan <- i
    }

    done := make(chan struct{})
    go func() {
        close(done)
        close(inputChan)
        close(outputChan)
        wg.Wait()
    }()

    for o := range outputChan {
        fmt.Println("reading from channel...")
        _output = append(_output, o)
    }

    <-done
    fmt.Printf("+++ output len: %v\n", len(_output))
    return _output, nil
}

func main() {
    List(5)
}

Solution de contournement

Le code dans la fonction principale est continu, D'abordessayez d'écrire 3k valeurs dans inputchan inputchan 然后将从 outputchanEnsuite

lisera les valeurs de outputchan code>. <p> </p>Votre code bloque dès la première étape : <ul> <li> <code>inputchan 之前,outputchan 不会流失任何内容,因此工作人员最终会在第一个 1k 值之后卡在 outputchan <- iEnvoyé avec succès une valeur de 3k à
  • inputchan 中消耗资源,main 将在大约 2k 个值之后卡在 inputchan <- iUne fois le personnel arrêté de
  • inputchan <- i) 和最终消费者 (for o := range outputchan {Une façon de résoudre ce problème est de faire exécuter le producteur (

    ) dans une goroutine séparée.

    Vous pouvez garder l'un de ces acteurs dans la goroutine principale et faire tourner un nouvel acteur pour l'autre. Par exemple :

    go func(inputchan chan<- int){
        for i := 0; i < 3000; i++ {
            inputchan <- i
        }
        close(inputchan)
    }(inputchan)
    
    done := make(chan struct{})
    go func() {
        close(done)
        // close(inputchan) // i chose to close inputchan above, don't close it twice
        close(outputchan)
        wg.wait()
    }()
    
    ...
    https://www.php.cn/link/80e4c54699b5b8cf8c67dd496909fceb

    done 的操作顺序很重要;通道 doneoutputchan 只能在 wg.done()Une note supplémentaire : une signalisation surround pour demander à tout le personnel de fermer une fois terminé

    🎜
    // it is best to close inputChan next to the code that controls
        // when its input is complete.
        close(inputChan)
        // If you had several producers writing to the same channel, you
        // would probably have to add a separate waitgroup to handle closing,
        // much like you did for your workers
    
        go func() {
            wg.Wait()
            // the two following actions must happen *after* workers have
            // completed
            close(done)
            close(outputChan)
        }()

    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:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer