#Golang Goroutine 函数 + for 的结果好怪异。
@meina 是的,这里的坑很容易掉进去
@meina 我这里图片还没显示出来,真让人捉急。。
不过文章应该很好的说明了你遇到的这个问题
The val variable in the above loops is actually a single variable that takes on the value of each slice element. Because the closures are all only bound to that one variable, there is a very good chance that when you run this code you will see the last element printed for every iteration instead of each value in sequence, because the goroutines will probably not begin executing until after the loop.
刚看完这篇文章。不是这个问题
可以在这里在线运行: https://play.golang.org/
package main
import (
"fmt"
"time"
)
func worker(id int, jobs <-chan int) {
fmt.Println("id",id)
for j := range jobs {
fmt.Println("worker", id, "started job", j)
//time.Sleep(time.Second)
}
}
func main() {
const numJobs = 5
jobs := make(chan int, numJobs)
for w := 1; w <= 3; w++ {
fmt.Println("id: ", w)
go worker(w, jobs)
}
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
time.Sleep(time.Second * 4)
}
@nil 多运行两次。然后观察打印的
fmt.Println("worker", id, "started job", j)
中的id
就很怪异。
@meina 怪异的id的原因就是文中提到的这个问题啊
@nil 似乎不太一样。
文中遍历的是普通变量。而我这个情况其实是遍历channel。
另一个朋友给了一个解释,我觉得能说通:并行读取chan变量时,顺序不固定。而上面那个for-range jobs就是这种情况。
改造了下,这个例子能证明上面的解释。
for j := 1; j <= numJobs; j++ {
jobs <- j
}
for i :=1; i<=5; i++{
go func() {
fmt.Println("jobs:", <- jobs)
}()
}
@nil 哎。其实就是我本来不理解为什么for-range chan是并行的。
@meina 其实是一样的问题,并行读取w和job时,顺序都是只有god知道,channel只是让这个问题更云里雾里了而已
你得先理解了go worker() 这里并发执行的机理,不要拿单进程的循环思路来理解并发
@nil 嗯,谢大佬。
@meina 还有个问题,一般我写for循环,都会写成
for i:=0; i<n; i++ 的形式,很少写
for i:=1; i<=n; i++
就像go的切片一样,会写成包含开始不包含结束的形式,除非一些特殊需求,这适用于所有语言
@nil 明白。我也是习惯从0开始,刚刚算是偶然。 ![]()
@nil 好。我在for range前面打印了下id,的确是123。
似乎加上了for range(channel)才令情况复杂起来的