为了账号安全,请及时绑定邮箱和手机立即绑定

函数退出后,goroutine如何从调用函数访问局部变量?

函数退出后,goroutine如何从调用函数访问局部变量?

Go
人到中年有点甜 2022-06-27 10:56:17
对golang相当陌生。我对 go 的变量范围有点困惑。我有以下玩具程序package mainimport "sync"import "time"import "fmt"import "math/rand"func main() {    go main_helper()    time.Sleep(time.Duration(1000000) * time.Millisecond)}func main_helper() {    rand.Seed(time.Now().UnixNano())    count := 0    finished := 0    var mu sync.Mutex    cond := sync.NewCond(&mu)    for i := 0; i < 10; i++ {        go func(i int) {            vote := requestVote(i)            mu.Lock()            defer mu.Unlock()            if vote {                count++            }            fmt.Printf("cur_count: %d\n", count)            finished++            cond.Broadcast()        }(i)    }    mu.Lock()    for count < 5 {        cond.Wait()    }    if count >= 5 {        println("received 5+ votes!")    } else {        println("lost")    }    mu.Unlock()    fmt.Printf("Exited main loop\n")}func requestVote(i int) bool {    if i > 6 {        time.Sleep(time.Duration(1000) * time.Millisecond)    } else {        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)    }    fmt.Printf("go routine: %d requested vote\n", i)    return true}在 Go 操场上运行此程序时,我得到以下输出:go routine: 0 requested votecur_count: 1go routine: 6 requested votecur_count: 2go routine: 1 requested votecur_count: 3go routine: 4 requested votecur_count: 4go routine: 2 requested votecur_count: 5received 5+ votes!Exited main loopgo routine: 3 requested votecur_count: 6go routine: 5 requested votecur_count: 7go routine: 7 requested votecur_count: 8go routine: 8 requested votecur_count: 9go routine: 9 requested votecur_count: 10这引发了一个问题,即main_helper()退出时,为什么局部变量不喜欢count并mu超出范围?为什么我们仍然看到未完成的 goroutine 正确更新计数变量?
查看完整描述

2 回答

?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

这是“逃逸分析”的结果。编译器意识到该变量count转义了函数main_helper,因为它在 goroutine 中使用,因此该变量是在堆上而不是在堆栈上分配的。通常,您可以返回指向局部变量的指针,并且由于转义分析,编译器会在堆上分配该变量,例如:


type X struct {

   ...

}


func NewX() *X {

  return &X{}

}

这是一种常见的类似构造函数的模式来初始化结构。这段代码相当于:


func NewX() *X {

  return new(X)

}

在您的程序中,count:=0声明相当于:


count:=new(int)

*count=0

并且 goroutine 保持一个指向count. 对finished.


查看完整回答
反对 回复 2022-06-27
?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

函数退出后,goroutine如何从调用函数访问局部变量?

任何符合 Go 语言规范的编译器都可以使用其作者选择实现的任何技术,例如将所有变量放在堆上,根本不释放内存,使用引用计数或仅将一些变量放在堆栈上。


查看完整回答
反对 回复 2022-06-27
  • 2 回答
  • 0 关注
  • 101 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号