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{
"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, "might be down!")
c <- link
return
}
fmt.Println(link, "is up!")
c <- 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?
>Solution :
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.