Dalam bidang pengaturcaraan serentak, Goroutine dan saluran memainkan peranan penting dalam melaksanakan corak komunikasi tak segerak. Walau bagaimanapun, memahami cara mereka berinteraksi dengan tamat masa boleh menjadi agak rumit.
Pertimbangkan coretan kod berikut:
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"})) }
Matlamat kod ini adalah untuk menentukan sama ada senarai URL boleh dicapai . Walau bagaimanapun, ia sentiasa kembali benar, tidak kira sama ada mana-mana URL tidak boleh dicapai. Mengapakah kes tamat masa tidak dilaksanakan?
Kunci untuk memahami isu ini terletak pada cara Goroutine dan saluran berinteraksi. Apabila check(u) dipanggil dalam Goroutine luar, ia menjeda pelaksanaan Goroutine tersebut selama 4 saat. Walau bagaimanapun, penyata pilih hanya dilaksanakan setelah check(u) kembali. Pada masa itu, kedua-dua cek(u) dan masa. Selepas cawangan sedia untuk dijalankan.
Untuk menangani isu ini, kami perlu mengasingkan check(u) dalam Goroutinenya sendiri:
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"})) }
Dalam kod yang disemak ini, semak(u) digunakan dalam Goroutine yang berasingan. Ini membolehkan pernyataan pilih membezakan dengan betul antara penyempurnaan semakan(u) dan keadaan tamat masa.
Sebagai alternatif, kami boleh memudahkan kod dengan menggunakan tamat masa tunggal untuk semua 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"})) }
Dalam versi ini, kami menggunakan saluran yang boleh menampung semua respons. Tamat masa ditetapkan kepada satu saat, dan hasil pertama yang tiba dalam saluran dikembalikan. Jika tiada URL boleh dicapai sebelum tamat masa tamat, saluran akan menerima nilai palsu.
Atas ialah kandungan terperinci Mengapa Tamat Masa Gagal dalam Saluran Go Apabila Menggunakan Goroutines?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!