这段 go 代码如何理解 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
thomaswang
V2EX    问与答

这段 go 代码如何理解

  •  
  •   thomaswang 2019-04-25 17:48:00 +08:00 3053 次点击
    这是一个创建于 2414 天前的主题,其中的信息可能已经有所发展或是发生改变。
    for i := 0; i < 10; i++ { go func() { fmt.Println("i: ", i) wg.Done() }() } 

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

    21 条回复    2019-04-30 11:34:57 +08:00
    rrfeng
        1
    rrfeng  
       2019-04-25 17:56:42 +08:00
    搜一下就可以了:go routine 变量继承

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

    调度器会在寻找可执行的 goroutine 时,M 会先在 local queue 找(也就是同一个 thread 上),也会随机偷 global queue 里等待执行的 goroutine
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2398 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 15:48 PVG 23:48 LAX 07:48 JFK 10:48
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86