Golang并发问题

问题描述 投票:0回答:2

我正在学习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)
  }
go concurrency
2个回答
5
投票

两个问题。首先,您创建了竞争条件。通过关闭循环变量,您可以在运行循环的线程和运行 goroutine 的线程之间共享它,这会导致您所描述的问题:当为第一个 URL 启动的 goroutine 尝试运行时,该值变量的值发生了变化。您需要将其复制到局部变量,或将其作为参数传递,例如:

for _, url := range urls {
    go func(url string) {
     fmt.Println(IsReachable(url)) 
     }(url)
}

其次,你说你想“按顺序”显示它们,这不是一个与并发/并行兼容的目标,因为你无法控制并行操作的顺序。如果您希望它们按顺序排列,则应该在单个线程中按顺序执行它们。否则,您必须收集结果,等待所有结果返回,然后将结果重新按所需顺序排序,然后再打印。


0
投票

上面的回答很贴切,会补充一些要点。

  • 2 个 go 例程由您引用变量 bing
  • 您编写的解决方案本质上不能是确定性的,即第一个旋转的 go 例程将首先执行,它完全取决于 go 运行时
  • 添加时间。睡眠也是一种不好的方法,您应该使用sync.Waitgroup或频道的方法。
© www.soinside.com 2019 - 2024. All rights reserved.