这段 go 代码如何理解

2019-04-25 17:48:00 +08:00
 thomaswang
for i := 0; i < 10; i++ {
	go func() {
		fmt.Println("i: ", i)
		wg.Done()
	}()
}

这个新开的 goroutein 应该是一个新的函数栈吧, 为什么它可以拿到 i 呢,

2746 次点击
所在节点    问与答
21 条回复
rrfeng
2019-04-25 17:56:42 +08:00
搜一下就可以了:go routine 变量继承

go 在编译时进行逃逸分析,发现 i 被使用就放到堆里去了。如果没使用就放栈里。
Reficul
2019-04-25 17:57:10 +08:00
闭包呀
KgM4gLtF0shViDH3
2019-04-25 18:42:32 +08:00
@rrfeng #1 是闭包捕获吧
Vegetable
2019-04-25 18:45:45 +08:00
下一个问是:fmt 前加上 sleep 1s,打印出来的结果是什么:doge
gamexg
2019-04-25 20:09:42 +08:00
@Vegetable #4 他这不加 sleep 结果一般也会符合预期的不正确。
thomaswang
2019-04-25 20:18:39 +08:00
@rrfeng 你说的是 func a 调 func b,b 直接把局部变量返回给 a 吗
beiping96
2019-04-25 20:22:43 +08:00
1. 闭包
2. 打印的全是 10 (不是 9 )
xdeng
2019-04-25 20:54:29 +08:00
@beiping96 好点电脑会小点
JaguarJack
2019-04-25 20:59:23 +08:00
@beiping96 应该是不确定的
thomaswang
2019-04-25 21:04:46 +08:00
@rrfeng 你说的也是对的, 必报捕获也是你这个逃逸
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()
}()
}
```
thomaswang
2019-04-25 23:53:05 +08:00
@sunjourney 那你解释一下第二个方法闭包里面为什么可以拿到 i
mengzhuo
2019-04-26 00:26:24 +08:00
1. i 是一个内存上的地址
2. 当 goroutine 是创建时会*拷贝*一份执行栈上的数据, 但不运行
3. i=10 时,循环结束主 goroutine 暂停,调度器开始寻找可以执行的 goroutine
4. 其他 goroutine 的作用域中并没有 i 这个本地变量,开始向上查找
5. 找到主 goroutine 中的 i , 此时 i =10 并打印。
whoami9894
2019-04-26 00:31:52 +08:00
@mengzhuo
不太了解 goroutine 的调度机制,如果是多核多调度器是有可能打印出非十个 10 吧
jadeity
2019-04-26 06:22:24 +08:00
@whoami9894 实际也不是十个 10,这是一个不可预测的结果,如果按照楼主的写法 go vet 会警告的。
respect11
2019-04-26 08:57:59 +08:00
thomaswang
2019-04-26 09:36:31 +08:00
@mengzhuo 第三条,主 routine 和各个子 routine 是调度器去调度, 执行顺序没法控制吧, 第 2 条, 拷贝一份执行栈上的数据, 和第四条, 向上查找,有详细的结束资料吗, 我怎么找不到啊
thomaswang
2019-04-26 09:36:49 +08:00
@respect11 ?, 不是我
respect11
2019-04-26 09:41:36 +08:00
@thomaswang #18 刚差点看错。。
sunjourney
2019-04-26 13:43:47 +08:00
@thomaswang #12 这还要解释?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/558692

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX