for i := 0; i < 10; i++ {
go func() {
fmt.Println("i: ", i)
wg.Done()
}()
}
这个新开的 goroutein 应该是一个新的函数栈吧, 为什么它可以拿到 i 呢,
1
rrfeng 2019-04-25 17:56:42 +08:00
搜一下就可以了:go routine 变量继承
go 在编译时进行逃逸分析,发现 i 被使用就放到堆里去了。如果没使用就放栈里。 |
2
Reficul 2019-04-25 17:57:10 +08:00
闭包呀
|
3
KgM4gLtF0shViDH3 2019-04-25 18:42:32 +08:00 via iPhone
@rrfeng #1 是闭包捕获吧
|
4
Vegetable 2019-04-25 18:45:45 +08:00
下一个问是:fmt 前加上 sleep 1s,打印出来的结果是什么:doge
|
6
thomaswang OP @rrfeng 你说的是 func a 调 func b,b 直接把局部变量返回给 a 吗
|
7
beiping96 2019-04-25 20:22:43 +08:00
1. 闭包
2. 打印的全是 10 (不是 9 ) |
9
JaguarJack 2019-04-25 20:59:23 +08:00 via iPhone
@beiping96 应该是不确定的
|
10
thomaswang OP @rrfeng 你说的也是对的, 必报捕获也是你这个逃逸
|
11
sunjourney 2019-04-25 21:04:52 +08:00
你的例子确定是愿意吗?
如果要打印 1 到 9 应该这么写: ```go var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(i int) { fmt.Println("i: ", i) wg.Done() }(i) } ``` 或者 ```go var wg sync.WaitGroup for i := 0; i < 10; i++ { j := i wg.Add(1) go func() { fmt.Println("i: ", j) wg.Done() }() } ``` |
12
thomaswang OP @sunjourney 那你解释一下第二个方法闭包里面为什么可以拿到 i
|
13
mengzhuo 2019-04-26 00:26:24 +08:00 via iPhone
1. i 是一个内存上的地址
2. 当 goroutine 是创建时会*拷贝*一份执行栈上的数据, 但不运行 3. i=10 时,循环结束主 goroutine 暂停,调度器开始寻找可以执行的 goroutine 4. 其他 goroutine 的作用域中并没有 i 这个本地变量,开始向上查找 5. 找到主 goroutine 中的 i , 此时 i =10 并打印。 |
14
whoami9894 2019-04-26 00:31:52 +08:00 via Android
@mengzhuo
不太了解 goroutine 的调度机制,如果是多核多调度器是有可能打印出非十个 10 吧 |
15
jadeity 2019-04-26 06:22:24 +08:00
@whoami9894 实际也不是十个 10,这是一个不可预测的结果,如果按照楼主的写法 go vet 会警告的。
|
16
respect11 2019-04-26 08:57:59 +08:00
|
17
thomaswang OP @mengzhuo 第三条,主 routine 和各个子 routine 是调度器去调度, 执行顺序没法控制吧, 第 2 条, 拷贝一份执行栈上的数据, 和第四条, 向上查找,有详细的结束资料吗, 我怎么找不到啊
|
18
thomaswang OP @respect11 ?, 不是我
|
19
respect11 2019-04-26 09:41:36 +08:00
@thomaswang #18 刚差点看错。。
|
20
sunjourney 2019-04-26 13:43:47 +08:00
@thomaswang #12 这还要解释?
|
21
mengzhuo 2019-04-30 11:34:57 +08:00
@thomaswang
注意: 这是*并发*,不是*并行* 调度顺序没办法预测的 调度器会在寻找可执行的 goroutine 时,M 会先在 local queue 找(也就是同一个 thread 上),也会随机偷 global queue 里等待执行的 goroutine |