对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.

繁星点点滴滴
TA贡献1803条经验 获得超3个赞
函数退出后,goroutine如何从调用函数访问局部变量?
任何符合 Go 语言规范的编译器都可以使用其作者选择实现的任何技术,例如将所有变量放在堆上,根本不释放内存,使用引用计数或仅将一些变量放在堆栈上。
- 2 回答
- 0 关注
- 101 浏览
添加回答
举报
0/150
提交
取消