我正在学习Golang并发并编写了一个程序来按顺序显示URL。我希望代码能返回
http://bing.com*
http://google.com*
但它总是返回 http://google.com*** 。就好像变量被覆盖一样。因为我使用的是 goroutine,所以我希望它同时返回两个值。
func check(u string) string {
tmpres := u+"*****"
return tmpres
}
func IsReachable(url string) string {
ch := make(chan string, 1)
go func() {
ch <- check(url)
}()
select {
case reachable := <-ch:
// use err and reply
return reachable
case <-time.After(3* time.Second):
// call timed out
return "none"
}
}
func main() {
var urls = []string{
"http://bing.com/",
"http://google.com/",
}
for _, url := range urls {
go func() {
fmt.Println(IsReachable(url))
}()
}
time.Sleep(1 * time.Second)
}
两个问题。首先,您创建了竞争条件。通过关闭循环变量,您可以在运行循环的线程和运行 goroutine 的线程之间共享它,这会导致您所描述的问题:当为第一个 URL 启动的 goroutine 尝试运行时,该值变量的值发生了变化。您需要将其复制到局部变量,或将其作为参数传递,例如:
for _, url := range urls {
go func(url string) {
fmt.Println(IsReachable(url))
}(url)
}
其次,你说你想“按顺序”显示它们,这不是一个与并发/并行兼容的目标,因为你无法控制并行操作的顺序。如果您希望它们按顺序排列,则应该在单个线程中按顺序执行它们。否则,您必须收集结果,等待所有结果返回,然后将结果重新按所需顺序排序,然后再打印。
上面的回答很贴切,会补充一些要点。