美文网首页Golang语言社区go学习Go语言用例
goroutine访问宿主函数局部变量

goroutine访问宿主函数局部变量

作者: CodingCode | 来源:发表于2017-09-17 16:10 被阅读24次

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

package main

import (
  "log"
  "time"
)

func foo() {
  defer log.Println("defer foo()")
  i := int(1);
  j := int(2);

  go func (p int) {
    defer log.Println("defer goroute")
    for k := 0; k < 5; k++ {
      i += 10
      log.Printf("p=%d,i=%d\n", p, i)
      time.Sleep(2*time.Second)
    }
    log.Println("exit of goroute")
  }(i)

  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=111
2017/09/17 15:58:50 p=1,i=321
2017/09/17 15:58:52 p=1,i=531
2017/09/17 15:58:53 exit of foo
2017/09/17 15:58:53 defer foo()
2017/09/17 15:58:54 p=1,i=541
2017/09/17 15:58:56 p=1,i=551
2017/09/17 15:58:58 exit of goroute
2017/09/17 15:58:58 defer goroute
2017/09/17 15:59:01 exit of main
2017/09/17 15:59:01 defer main

or

2017/09/17 15:59:05 p=1,i=111
2017/09/17 15:59:07 p=1,i=221
2017/09/17 15:59:09 p=1,i=431
2017/09/17 15:59:10 exit of foo
2017/09/17 15:59:10 defer foo()
2017/09/17 15:59:11 p=1,i=541
2017/09/17 15:59:13 p=1,i=551
2017/09/17 15:59:15 exit of goroute
2017/09/17 15:59:15 defer goroute
2017/09/17 15:59:18 exit of main
2017/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(SB), AX
  0x00dd 00221 (/.../src/main/main.go:11)  MOVQ  AX, (SP)
  0x00e1 00225 (/.../src/main/main.go:11)  PCDATA  $0, $1
  0x00e1 00225 (/.../src/main/main.go:11)  CALL  runtime.newobject(SB)
  0x00e6 00230 (/.../main/main.go:11)  MOVQ  8(SP), AX
  0x00eb 00235 (/.../src/main/main.go:11)  MOVQ  AX, "".&i+104(SP)
  0x00f0 00240 (/.../src/main/main.go:11)  MOVQ  $1, (AX)
  0x00f7 00247 (/.../src/main/main.go:12)  MOVQ  $2, "".j+48(SP)

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

相关文章

  • goroutine访问宿主函数局部变量

    我们知道goroutine函数会在一个不同于当前调用者线程的环境中运行;那么当调用者线程结束,或者调用者函数返回之...

  • Python变量作用域

    变量作用域 局部变量 定义在函数内部的变量,叫局部变量 局部变量函数内部访问使用,函数外部不能访问使用 上述代码运...

  • javascript summary

    全局变量和局部变量 局部变量 局部变量是在函数内部使用var申明的变量,只能在函数内任意访问,函数外部是无法访问到...

  • js闭包

    js中任何函数可以访问全局变量,但是局部变量除了访问自己内部的局部变量和自己上级的局部变量之外无法访问别的函数的局...

  • 闭包

    闭包是定义在一个函数内部可访问该函数内部局部变量的函数,作用就是让函数外部可以访问函数内部局部变量。 举个栗子: ...

  • 2019-07-24js如何获取函数内的变量

    众所周知,js函数内部的局部变量,外界是访问不到的。那么js中是如何访问函数内部的局部变量。 今天有个很简单的需求...

  • js 中闭包初步

    js中由于作用域链,函数里var定义的变量是局部变量,函数外并不能访问到函数里定义的局部变量,函数外定义的变...

  • 第二十章 闭包和cookie

    一,闭包 概念:在函数外部访问其内部的局部变量的函数叫做闭包。 原理:通过匿名函数 将局部变量驻留在内存当中,达到...

  • JavaScript 闭包、定时器

    什么是闭包? 有什么作用 因为js只存在局部变量和全局变量,函数内部可以访问外部变量,而外部却不能访问局部变量。闭...

  • 什么是闭包

    什么是闭包? 在上面的代码中,函数A有一个局部变量a,有一个函数B,B中可以访问函数A中的局部变量A,这就形成了一...

网友评论

    本文标题:goroutine访问宿主函数局部变量

    本文链接:https://www.haomeiwen.com/subject/indjsxtx.html