Heim  >  Artikel  >  Backend-Entwicklung  >  Der letzte über den Kanal in der Haupt-Goroutine Golang gesendete Wert konnte nicht empfangen werden

Der letzte über den Kanal in der Haupt-Goroutine Golang gesendete Wert konnte nicht empfangen werden

WBOY
WBOYnach vorne
2024-02-09 11:33:09495Durchsuche

主 goroutine Golang 中无法接收沿通道发送的最后一个值

Der letzte über den Kanal in der Haupt-Goroutine Golang gesendete Wert kann nicht empfangen werden. Dies liegt daran, dass die Goroutine beim Schließen des Kanals keine neuen Werte mehr empfangen kann. Stattdessen blockiert es den Empfangsvorgang, bis alle Werte im Kanal empfangen wurden. Dies ist eine Entwurfsentscheidung in Golang, um mögliche Deadlock-Situationen während Empfangsvorgängen zu vermeiden. Daher müssen wir beim Schreiben von Golang-Programmen besonders darauf achten, um mögliche Probleme und Fehler zu vermeiden.

Frageninhalt

Gegebener TCP-Port-Scanner in Golang. 2 Implementierungen, die erste stammt von mir und die zweite stammt aus dem Golang-Buch. Gehen Sie davon aus, dass die zweite Variante zu 100 % machbar ist, wie viele Leser bereits getestet haben. Aber es scheint, dass beide das gleiche Problem haben: Der letzte im Ergebniskanal gesendete Wert kann in der Hauptkoroutine nicht empfangen werden, sie bleibt hängen und wartet endlos auf den Wert vom Kanal, obwohl der Wert tatsächlich gesendet wird. Einige Beobachtungen: Wenn die Anzahl der Ports weniger als 21 beträgt, funktioniert es wie erwartet; wenn die Anzahl 1000 übersteigt, erhöht sich die nicht empfangene Menge auf etwa 10. Ich verstehe nicht warum.

Umsetzung im Buch

func worker(ports, results chan int) {
    for p := range ports {
        address := fmt.Sprintf("scanme.nmap.org:%d", p)
        conn, err := net.Dial("tcp", address)
        if err != nil {
            results <- 0
            fmt.Println("sent", p)
            continue
        }
        conn.Close()
        results <- p
        fmt.Println("sent", p)
    }
}

func main() {
    ports := make(chan int, 100)
    results := make(chan int)

    var openports []int

    for i := 0; i < cap(ports); i++ {
        go worker(ports, results)
    }

    go func() {
        for i := 1; i <= 50; i++ {
            ports <- i
        }
    }()

    for i := 0; i < 50; i++ {
        port := <-results // after 49 it gets stuck infinitely, never proceed further
        fmt.Println("received", port, i)
        if port != 0 {
            openports = append(openports, port)
        }
    }

    close(ports)
    close(results)

    sort.Ints(openports)

    fmt.Println(openports)

}

Workaround

Dieses Problem wurde durch Hinzufügen einer Zeitüberschreitung zu net.Dialer gelöst

func worker(ports, results chan int) {
    dialer := net.Dialer{Timeout: time.Second}

    for p := range ports {
        address := fmt.Sprintf("scanme.nmap.org:%d", p)
        conn, err := dialer.Dial("tcp", address)
        if err != nil {
            results <- 0
            continue
        }

        conn.Close()
        results <- p
    }
}

Das obige ist der detaillierte Inhalt vonDer letzte über den Kanal in der Haupt-Goroutine Golang gesendete Wert konnte nicht empfangen werden. 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