check(u)
dormirà nella corrente goroutine, ovvero quello in esecuzione func
. L'istruzione select
viene eseguita correttamente solo una volta che viene restituita e, a quel punto, entrambe le diramazioni sono eseguibili e il runtime può selezionare quello che preferisce.
È possibile risolverlo eseguendo check
dentro ancora un altro goroutine:
package main
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"}))
}
Sembra che si desidera controllare la raggiungibilità di un insieme di URL, e ritornare vero se uno di loro è a disposizione. Se il timeout è lungo rispetto al tempo necessario per avviare una goroutine, è possibile semplificarlo avendo un solo timeout per tutti gli URL insieme. Ma abbiamo bisogno di fare in modo che il canale è abbastanza grande da contenere le risposte da tutti i controlli, o quelli che non "vincere" bloccherà per sempre:
package main
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"}))
}
Grazie. In realtà, voglio tornare non raggiungibile se uno di essi non è raggiungibile. Quindi la funzione di controllo può scrivere "false" sul canale solo se non riesce a raggiungere l'url (e non scrive nulla se raggiunge l'url) entro il timeout e l'ora. AfterFunc può scrivere true dopo il timeout totale. – Kamal