goroutine函数还能不能使用调用者函数的局部变量

时间:2019-09-30 15:30来源:快三平台下载编程
我们知道goroutine函数会在一个不同于当前调用者线程的环境中运行;那么当调用者线程结束,或者调用者函数返回之后,goroutine函数还能不能使用调用者函数的局部变量呢。下面代码例

我们知道goroutine函数会在一个不同于当前调用者线程的环境中运行;那么当调用者线程结束,或者调用者函数返回之后,goroutine函数还能不能使用调用者函数的局部变量呢。下面代码例子描述这个问题

package mainimport ( "log" "time")func foo() { defer log.Println("defer foo i := int; j := int; go func  { defer log.Println("defer goroute") for k := 0; k < 5; k++ { i += 10 log.Printf("p=%d,i=%dn", p, i) time.Sleep(2*time.Second) } log.Println("exit of goroute") } for k := 0; k < 5; k++ { i += 100 j += 100 time.Sleep(1*time.Second) } log.Println("exit of foo")}func main() { defer log.Println("defer main") foo() for j := 0; j < 8; j++ { time.Sleep(1*time.Second) } log.Println("exit of main")}

首先main函数会调用foo函数,foo函数内部会起来一个匿名goroutine,在这个匿名routine里面会访问foo的局部变量i。函数里面的time.Sleep()语句用来保证foo函数优先结束,然后是匿名goroutine,最后是main主函数。运行结果如下:

2017/09/17 15:58:48 p=1,i=1112017/09/17 15:58:50 p=1,i=3212017/09/17 15:58:52 p=1,i=5312017/09/17 15:58:53 exit of foo2017/09/17 15:58:53 defer foo()2017/09/17 15:58:54 p=1,i=5412017/09/17 15:58:56 p=1,i=5512017/09/17 15:58:58 exit of goroute2017/09/17 15:58:58 defer goroute2017/09/17 15:59:01 exit of main2017/09/17 15:59:01 defer mainor2017/09/17 15:59:05 p=1,i=1112017/09/17 15:59:07 p=1,i=2212017/09/17 15:59:09 p=1,i=4312017/09/17 15:59:10 exit of foo2017/09/17 15:59:10 defer foo()2017/09/17 15:59:11 p=1,i=5412017/09/17 15:59:13 p=1,i=5512017/09/17 15:59:15 exit of goroute2017/09/17 15:59:15 defer goroute2017/09/17 15:59:18 exit of main2017/09/17 15:59:18 defer main

可以看到匿名goroutine函数正常的使用了foo函数中定义的局部变量i,尽管函数foo已经退出,并且foo的defer部分已经执行了,那为什么局部变量i还能继续需用呢?答案是我们在前面文章也分析过了,go语言编译器会根据变量的逃逸分析,自动做出选择把一个变量分配的堆还是栈,在这个例子中很显然局部变量i被分配在了堆中。

我们看一下foo的汇编代码片段;为了便于区分,foo同时定义了两个局部变量i和j,i被goroutine使用了,而j没有:

 0x00d6 00214 (/.../src/main/main.go:10) LEAQ type.int, AX 0x00dd 00221 (/.../src/main/main.go:11) MOVQ AX,  0x00e1 00225 (/.../src/main/main.go:11) PCDATA $0, $1 0x00e1 00225 (/.../src/main/main.go:11) CALL runtime.newobject 0x00e6 00230 (/.../main/main.go:11) MOVQ 8, AX 0x00eb 00235 (/.../src/main/main.go:11) MOVQ AX, "".&i+104 0x00f0 00240 (/.../src/main/main.go:11) MOVQ $1,  0x00f7 00247 (/.../src/main/main.go:12) MOVQ $2, "".j+48

可以看出i被分配到了堆里面通过runtime.newobject出一个对象,而j直接分配在了栈上;所以不管foo是否已经退出,匿名goroutine都可以在堆中访问到i的值。

编辑:快三平台下载编程 本文来源:goroutine函数还能不能使用调用者函数的局部变量

关键词: