我想这是一个相当容易的修复。只是尝试遍历字符串列表urls
,并在循环迭代时打印出每个url
。但是当我添加并发(go
和WaitGroup
)时,它打印出来的是列表中最后一个url
。
为什么它只打印出最后一个url
(当从匿名函数打印时),而不是每个url
单独作为循环迭代?
Go Playground: http://play.golang.org/p/z4IZLY7Mt_
代码:
package main
import (
"fmt"
"sync"
)
var urls = []string{
"http://google.com",
"http://facebook.com",
"http://youtube.com",
"http://yahoo.com",
"http://baidu.com",
"http://wikipedia.org",
"http://twitter.com",
"http://live.com",
"http://amazon.com",
"http://linkedin.com",
"http://google.co.in",
}
func main() {
var wg sync.WaitGroup
for _, url := range urls {
fmt.Println("correct: " + url)
wg.Add(1)
go func() {
fmt.Println("wrong: " + url)
wg.Done()
}()
}
wg.Wait()
}
工作代码:
package main
import (
"fmt"
"sync"
)
var urls = []string{
"http://google.com",
"http://facebook.com",
"http://youtube.com",
"http://yahoo.com",
"http://baidu.com",
"http://wikipedia.org",
"http://twitter.com",
"http://live.com",
"http://amazon.com",
"http://linkedin.com",
"http://google.co.in",
}
func main() {
var wg sync.WaitGroup
for _, url := range urls {
fmt.Println("correct: " + url)
wg.Add(1)
go func(url string) {
fmt.Println("wrong: " + url)
wg.Done()
}(url)
}
wg.Wait()
}
也在go playground: http://play.golang.org/p/zFSDvfdIDS
添加我的答案,因为被接受的答案没有解释为什么。
Go中的闭包可以访问创建它的作用域的所有变量。因此,在下面的例子中创建的每个闭包都可以访问循环变量url
。
func main() {
var wg sync.WaitGroup
for _, url := range urls {
fmt.Println("correct: " + url)
wg.Add(1)
go func() {
fmt.Println("wrong: " + url)
wg.Done()
}()
}
wg.Wait()
}
因此,当每个闭包开始并发运行时,url
的值可以是urls
片中的任何元素(在大多数情况下是最后一个元素,但不是每次都是),因为它不会阻塞main
go例程。为了为每个闭包使用正确的值,我们需要复制要使用的正确值。例如,您可以这样做:
func main() {
var wg sync.WaitGroup
for _, url := range urls {
fmt.Println("correct: " + url)
url2 = url
wg.Add(1)
go func() {
fmt.Println("wrong: " + url2)
wg.Done()
}()
}
wg.Wait()
}
或者可以做前一个答案中已经存在的事情,这更显式和可读:
func main() {
var wg sync.WaitGroup
for _, url := range urls {
fmt.Println("correct: " + url)
wg.Add(1)
go func(url string) {
fmt.Println("wrong: " + url)
wg.Done()
}(url)
}
wg.Wait()
}