Heim >Backend-Entwicklung >Golang >Was sind die Ursachen für Deadlocks im Go-Code, der WaitGroups und Buffered Channels verwendet?

Was sind die Ursachen für Deadlocks im Go-Code, der WaitGroups und Buffered Channels verwendet?

PHPz
PHPznach vorne
2024-02-09 11:09:30782Durchsuche

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

php-Editor Baicao beantwortet in diesem Artikel eine häufig gestellte Frage: „Was ist der Grund für einen Deadlock im Go-Code mit WaitGroups und Buffered Channels?“ In der Go-Sprache sind WaitGroups und Buffered Channels häufig verwendete Tools für die gleichzeitige Programmierung. Manchmal kann es jedoch im Code, der sie verwendet, zu Deadlock-Situationen kommen. In diesem Artikel werden die Ursachen von Deadlocks untersucht und Lösungen bereitgestellt, die den Lesern helfen, dieses Problem zu vermeiden. Egal, ob Sie Anfänger oder erfahrener Go-Entwickler sind, dieser Artikel liefert Ihnen wertvolle Informationen.

Frageninhalt

Wartegruppen, Pufferkanäle und Deadlocks

Dieser Code von mir verursacht einen Deadlock, aber ich bin mir nicht sicher, warum. Ich habe versucht, Mutexe an verschiedenen Stellen zu verwenden und Kanäle innerhalb und außerhalb separater Go-Routinen zu schließen, aber immer noch das gleiche Ergebnis.

Ich versuche, Daten über einen Kanal (Inputchan) zu senden und dann Daten von einem anderen Kanal (Outputchan) zu lesen

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)
}

Workaround

Der Code in der Hauptfunktion ist kontinuierlich, Zuerstversuchen Sie, 3k Werte in inputchan zu schreiben inputchan 然后将从 outputchanDann

liest die Werte aus outputchan Code>. <p> </p>Ihr Code blockiert den ersten Schritt: <ul> <li> <code>inputchan 之前,outputchan 不会流失任何内容,因此工作人员最终会在第一个 1k 值之后卡在 outputchan <- iDer Wert von 3.000 wurde erfolgreich an
  • gesendet inputchan 中消耗资源,main 将在大约 2k 个值之后卡在 inputchan <- iSobald das Personal aufhört
  • inputchan <- i) 和最终消费者 (for o := range outputchan {Eine Möglichkeit, dieses Problem zu lösen, besteht darin, den Produzenten (

    ) in einer separaten Goroutine laufen zu lassen.

    Sie können einen dieser Schauspieler in der Haupt-Goroutine behalten und einen neuen Schauspieler für den anderen einsetzen. Zum Beispiel:

    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()Eine zusätzliche Anmerkung: Surround-Signalisierung , um alle Mitarbeiter anzuweisen, zu schließen, wenn sie fertig sind

    🎜
    // 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)
        }()

    Das obige ist der detaillierte Inhalt vonWas sind die Ursachen für Deadlocks im Go-Code, der WaitGroups und Buffered Channels verwendet?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen