Go语言的协程——Goroutine。进程(Process),线程(Thread),协程(Coroutine,也叫轻量级线程)
当使用并发闭包时,可能会引起一些混乱。 看一下以下程序:
func main() {
done := make(chan bool)
values := []string{"a", "b", "c"}
for _, v := range values {
go func() {
fmt.Println(v)
done <- true
}()
}
// wait for all goroutines to complete before exiting
for _ = range values {
<-done
}
}
人们可能会错误地认为a、b、c是输出。但实际上可能会看到的会是c, c, c。这是因为循环的每次迭代都使用变量v的相同实例,所以每个闭包共享这个单一变量。当闭包运行时,它会在执行fmt.Println时打印v的值,但v可能在goroutine启动后被修改过。为了在这些问题发生之前帮助检测它们,可以运行go vet。
要在启动每个闭包时将v的当前值绑定到它,必须修改内部循环以在每次迭代时创建一个新的变量。一种方法是将变量作为参数传递给闭包:
for _, v := range values {
go func(u string) {
fmt.Println(u)
done <- true
}(v)
}
在这个例子中,v的值作为参数传递给匿名函数。这个值可以在函数内部作为变量u访问。 更简单的方法是创建一个新的变量,使用一种看似奇怪但在Go中运行良好的声明样式:
for _, v := range values {
v := v // create a new 'v'.
go func() {
fmt.Println(v)
done <- true
}()
}
这种奇怪的行为,没有为每次迭代定义一个新的变量,现在看来,它的出现可能是一个错误。它可能在以后的版本中解决,但为了兼容性,不能在Go 1中更改。
外文翻译计划golang.org/doc/faq#clo…