Go: Timeouts mit Kanälen verwenden
In Go bieten Timeouts und Kanäle eine bequeme Möglichkeit, die Ausführung von Goroutinen zu steuern und ihre Ergebnisse zu synchronisieren . Es gibt jedoch bestimmte Szenarien, in denen der Timeout-Fall möglicherweise nicht wie erwartet ausgeführt wird.
Problembeschreibung
Beachten Sie den folgenden Go-Code:
import "fmt" import "time" func check(u string) bool { time.Sleep(4 * time.Second) return true } func IsReachable(urls []string) bool { ch := make(chan bool, 1) for _, url := range urls { go func(u string) { select { case ch <- check(u): case <-time.After(time.Second): ch <- false } }(url) } return <-ch } func main() { fmt.Println(IsReachable([]string{"url1"})) }
Das Ziel dieses Codes besteht darin, zu überprüfen, ob alle URLs in der bereitgestellten Liste erreichbar sind. Wenn eine URL nicht innerhalb einer Sekunde antwortet, sollte die Funktion „false“ zurückgeben.
Bei der Ausführung dieses Codes wird jedoch immer „true“ zurückgegeben. Der Timeout-Fall wird nicht ausgeführt.
Erklärung
Das Problem entsteht durch die Art und Weise, wie check(u) ausgeführt wird. In der IsReachable-Funktion prüft jede Goroutine die Erreichbarkeit einer URL, indem sie check(u) aufruft. check(u) schläft jedoch 4 Sekunden lang in der aktuellen Goroutine, bevor es zurückkehrt.
Innerhalb der select-Anweisung ist der case ch <- check(u): Branch der erste, der verfügbar wird, da check( u) ist bereits zurückgekehrt. Dies verhindert, dass der Timeout-Fall jemals ausgeführt wird, was dazu führt, dass die Funktion immer „true“ zurückgibt.
Lösung
Um dieses Problem zu beheben, sollte die Funktion check(u) ausgeführt werden in einer separaten Goroutine. Dadurch kann die Select-Anweisung den Timeout-Fall ordnungsgemäß behandeln.
Hier ist der aktualisierte Code:
import "fmt" import "time" func check(u string, checked chan<- bool) { time.Sleep(4 * time.Second) checked <- true } func IsReachable(urls []string) bool { ch := make(chan bool, 1) for _, url := range urls { go func(u string) { checked := make(chan bool) go check(u, checked) select { case ret := <-checked: ch <- ret case <-time.After(1 * time.Second): ch <- false } }(url) } return <-ch } func main() { fmt.Println(IsReachable([]string{"url1"})) }
Wenn nun eine der URLs nicht innerhalb einer Sekunde antwortet, kehrt die Funktion zurück FALSCH. Wenn nur eine URL verfügbar ist, gibt die Funktion außerdem true zurück.
Das obige ist der detaillierte Inhalt vonWarum funktioniert mein Go-Timeout in diesem Kanalbeispiel nicht?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!