在 Go 中使用超时和通道
Goroutines 和通道为 Go 中的并发编程提供了强大的机制。然而,处理 goroutine 中的超时可能会很棘手。
在您想要使用 goroutine 和超时检查 URL 列表的可达性的场景中,可能存在超时不会被执行的情况,即使一些 URL 无法访问。
让我们分析一下提供的代码:
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 }
问题出在 check 函数中。当你在 goroutine 中使用 time.Sleep 时,它会暂停当前的 goroutine,在本例中是运行 check 函数的 goroutine。当 check 函数暂停时,外层 goroutine 中的 select 语句仍会尝试运行。
在这种情况下,select 语句的两个分支(检查结果或超时)将在 4 年后运行检查返回时的秒数。然而,由于两个分支都是可运行的,运行时可以选择执行其中一个,这可能会导致始终返回 true。
要解决这个问题,您需要为每个检查函数创建一个新的 goroutine,如下所示更正后的代码如下:
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(time.Second): ch <- false } }(url) } return <-ch }
这种情况下,check函数是在一个单独的goroutine中执行的,确保它不会暂停外层goroutine,并且超时可以正确执行。
以上是如何在带通道的 Go Goroutine 中正确实现超时?的详细内容。更多信息请关注PHP中文网其他相关文章!