goroutines的输出错误

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

Incorrect output by goroutines

问题

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

以下是代码:

func main() {
	links := []string{
		"http://google.com",
		"http://facebook.com",
		"http://stackoverflow.com",
		"http://amazon.com",
		"http://golang.org",
	}

	c := make(chan string)

	for _, link := range links {
		go checkLink(link, c)
	}

	for l := range c {
		go func() {
			time.Sleep(5 * time.Second)
			checkLink(l, c)
		}()
	}
}

func checkLink(link string, c chan string) {
	_, err := http.Get(link)

	if err != nil {
		fmt.Println(link, "可能已经宕机!")
		c <- link
		return
	}
	fmt.Println(link, "正常运行!")
	c <- link
}

我得到的输出是:

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:

func main() {
	links := []string{
		&quot;http://google.com&quot;,
		&quot;http://facebook.com&quot;,
		&quot;http://stackoverflow.com&quot;,
		&quot;http://amazon.com&quot;,
		&quot;http://golang.org&quot;,
	}

	c := make(chan string)

	for _, link := range links {
		go checkLink(link, c)
	}

	for l := range c {
		go func() {
			time.Sleep(5 * time.Second)
			checkLink(l, c)
		}()
	}
}

func checkLink(link string, c chan string) {
	_, err := http.Get(link)

	if err != nil {
		fmt.Println(link, &quot;might be down!&quot;)
		c &lt;- link
		return
	}
	fmt.Println(link, &quot;is up!&quot;)
	c &lt;- link
}

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内部的匿名函数。下面是代码的更新版本:

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

通过将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:

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

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:

确定