goroutines的输出错误

huangapple go评论140阅读模式
英文:

Incorrect output by goroutines

问题

我正在观看一个讲座,作者在其中使用Go协程构建了一个状态应用程序,但在一段时间后表现出奇怪的行为。

以下是代码:

  1. func main() {
  2. links := []string{
  3. "http://google.com",
  4. "http://facebook.com",
  5. "http://stackoverflow.com",
  6. "http://amazon.com",
  7. "http://golang.org",
  8. }
  9. c := make(chan string)
  10. for _, link := range links {
  11. go checkLink(link, c)
  12. }
  13. for l := range c {
  14. go func() {
  15. time.Sleep(5 * time.Second)
  16. checkLink(l, c)
  17. }()
  18. }
  19. }
  20. func checkLink(link string, c chan string) {
  21. _, err := http.Get(link)
  22. if err != nil {
  23. fmt.Println(link, "可能已经宕机!")
  24. c <- link
  25. return
  26. }
  27. fmt.Println(link, "正常运行!")
  28. c <- link
  29. }

我得到的输出是:

http://stackoverflow.com 正常运行!

http://google.com 正常运行!

http://facebook.com 正常运行!

http://golang.org 正常运行!

http://amazon.com 正常运行!

http://amazon.com 正常运行!

http://amazon.com 正常运行!

http://amazon.com 正常运行!

http://amazon.com 正常运行!

http://amazon.com 正常运行!

我不明白为什么"amazon.com"一直重复出现在这里?为什么在打印了所有5个链接之后会发生这种情况?

英文:

I am watching a lecture in which author build a status app using go routines which is behaving weirdly after sometime.

Here's the code:

  1. func main() {
  2. links := []string{
  3. &quot;http://google.com&quot;,
  4. &quot;http://facebook.com&quot;,
  5. &quot;http://stackoverflow.com&quot;,
  6. &quot;http://amazon.com&quot;,
  7. &quot;http://golang.org&quot;,
  8. }
  9. c := make(chan string)
  10. for _, link := range links {
  11. go checkLink(link, c)
  12. }
  13. for l := range c {
  14. go func() {
  15. time.Sleep(5 * time.Second)
  16. checkLink(l, c)
  17. }()
  18. }
  19. }
  20. func checkLink(link string, c chan string) {
  21. _, err := http.Get(link)
  22. if err != nil {
  23. fmt.Println(link, &quot;might be down!&quot;)
  24. c &lt;- link
  25. return
  26. }
  27. fmt.Println(link, &quot;is up!&quot;)
  28. c &lt;- link
  29. }

The output I get is:

> http://stackoverflow.com is up!
>
> http://google.com is up!
>
> http://facebook.com is up!
>
> http://golang.org is up!
>
> http://amazon.com is up!
>
> http://amazon.com is up!
>
> http://amazon.com is up!
>
> http://amazon.com is up!
>
> http://amazon.com is up!
>
> http://amazon.com is up!

I don't understand why the "amazon.com" keeps on repeating here?? Why is this happening after all the 5 links has been printed?

答案1

得分: 1

问题出在闭包捕获循环变量l上。由于goroutine是在循环内部启动的,循环创建的所有goroutine共享相同的内存地址l。当休眠结束并执行goroutine时,由于循环迭代剩余的链接,l的值已经发生了变化。因此,所有的goroutine最终都会检查links切片中的最后一个链接,即**"http://amazon.com"**。

要解决这个问题,你需要将循环变量l作为参数传递给goroutine内部的匿名函数。下面是代码的更新版本:

  1. for l := range c {
  2. go func(link string) {
  3. time.Sleep(5 * time.Second)
  4. checkLink(link, c)
  5. }(l)
  6. }

通过将l作为参数传递给匿名函数,每个goroutine都会拥有自己的l的副本,保留了每次迭代的正确值。

英文:

The issue lies in the closure capturing of the loop variable l. Since the goroutine is started inside a loop, all goroutines created by the loop share the same memory address for l. By the time the sleep is over and the goroutine is executed, the value of l has changed due to the loop iterating over the remaining links. Consequently, all goroutines end up checking the last link in the links slice, which is "http://amazon.com".
To fix this, you need to pass the loop variable l as an argument to the anonymous function inside the goroutine. Here's an updated version of the code:

  1. for l := range c {
  2. go func(link string) {
  3. time.Sleep(5 * time.Second)
  4. checkLink(link, c)
  5. }(l)
  6. }

By passing l as an argument to the anonymous function, each goroutine will have its own copy of l, preserving the correct value for each iteration.

huangapple
  • 本文由 发表于 2023年7月2日 20:23:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76598877.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定