Dans le domaine de la programmation simultanée, les Goroutines et les canaux jouent un rôle central dans la mise en œuvre de modèles de communication asynchrones. Cependant, comprendre comment ils interagissent avec les délais d'attente peut être un peu délicat.
Considérez l'extrait de code suivant :
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"})) }
L'objectif de ce code est de déterminer si une liste d'URL est accessible. . Cependant, il renvoie toujours vrai, qu'une URL soit inaccessible ou non. Pourquoi le cas de délai d'attente n'est-il pas exécuté ?
La clé pour comprendre ce problème réside dans la façon dont les Goroutines et les canaux interagissent. Lorsque check(u) est appelé dans le Goroutine externe, il suspend l'exécution de ce Goroutine pendant 4 secondes. Cependant, l'instruction select ne s'exécute qu'une fois check(u) renvoyé. À ce moment-là, les branches check(u) et time.After sont prêtes à être exécutées.
Pour résoudre ce problème, nous devons isoler check(u) dans sa propre Goroutine :
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"})) }
Dans ce code révisé, check(u) est invoqué dans un Goroutine distinct. Cela permet à l'instruction select de faire la distinction correctement entre l'achèvement de check(u) et la condition d'expiration.
Alternativement, nous pourrions simplifier le code en utilisant un seul délai d'attente pour toutes les URL :
import "fmt" import "time" func check(u string, ch chan<- bool) { time.Sleep(4 * time.Second) ch <- true } func IsReachable(urls []string) bool { ch := make(chan bool, len(urls)) for _, url := range urls { go check(url, ch) } time.AfterFunc(time.Second, func() { ch <- false }) return <-ch } func main() { fmt.Println(IsReachable([]string{"url1", "url2"})) }
Dans cette version, nous utilisons un canal qui peut contenir toutes les réponses. Un délai d'attente est fixé à une seconde et le premier résultat arrivant dans le canal est renvoyé. Si aucune des URL n'est accessible avant l'expiration du délai d'attente, la chaîne recevra une fausse valeur.
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!