
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 akagishigeru 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 |