goroutine 中的 return 值发生了什么
What happens to return value from goroutine
有人可以从 goroutine 中给出澄清值 return。来自 goroutine 的 returned 值是否存储在 stake 中。
示例:
// function getNumber returns the "int i" and we can't use this returned value
// because this function is invoked as goroutine.
// We know that, to communicate between main and goroutine one could
// use the channel ( chan <- i), but I am interested to know about
// the use of return i in goroutine. Is it possible to get/ use this
// returned value.
func getNumber(i int) int {
return i
}
func main() {
for i:=0; i<10; i++ {
go printNumber(i)
}
time.Sleep(5)
}
我们是否应该尽量避免在 go routine 中使用 return 值?
快速查看汇编输出表明
$ go build -gcflags -S z.go
getNumber()
函数确实将其结果存储到堆栈中
"".getNumber t=1 size=16 value=0 args=0x10 locals=0x0
0x0000 00000 (z.go:5) TEXT "".getNumber+0(SB),4,[=11=]-16
0x0000 00000 (z.go:6) MOVQ "".i+8(FP),BX
0x0005 00005 (z.go:6) MOVQ BX,"".~r1+16(FP)
0x000a 00010 (z.go:6) RET ,
所以当它被一个 goroutine 调用时,它会将它的结果存储到堆栈中。然而,这是一个新堆栈,在 goroutine 结束时被销毁,因此不可能检索 return 值。
"".main t=1 size=96 value=0 args=0x0 locals=0x18
0x0000 00000 (z.go:9) TEXT "".main+0(SB),-0
0x0000 00000 (z.go:9) MOVQ (TLS),CX
0x0009 00009 (z.go:9) CMPQ SP,16(CX)
0x000d 00013 (z.go:9) JHI ,22
0x000f 00015 (z.go:9) CALL ,runtime.morestack_noctxt(SB)
0x0014 00020 (z.go:9) JMP ,0
0x0016 00022 (z.go:9) SUBQ ,SP
0x001a 00026 (z.go:10) MOVQ [=12=],AX
0x001c 00028 (z.go:10) CMPQ AX,
0x0020 00032 (z.go:10) JGE [=12=],74
0x0022 00034 (z.go:11) MOVQ AX,"".i+16(SP)
0x0027 00039 (z.go:11) MOVQ AX,(SP)
0x002b 00043 (z.go:11) MOVQ $"".getNumber·f+0(SB),CX
0x0032 00050 (z.go:11) PUSHQ CX,
0x0033 00051 (z.go:11) PUSHQ ,
0x0035 00053 (z.go:11) PCDATA [=12=],[=12=]
0x0035 00053 (z.go:11) CALL ,runtime.newproc(SB)
0x003a 00058 (z.go:11) POPQ ,CX
0x003b 00059 (z.go:11) POPQ ,CX
0x003c 00060 (z.go:10) MOVQ "".i+16(SP),AX
0x0041 00065 (z.go:10) INCQ ,AX
0x0044 00068 (z.go:10) NOP ,
0x0044 00068 (z.go:10) CMPQ AX,
0x0048 00072 (z.go:10) JLT [=12=],34
0x004a 00074 (z.go:13) MOVQ ,(SP)
0x0052 00082 (z.go:13) PCDATA [=12=],[=12=]
0x0052 00082 (z.go:13) CALL ,time.Sleep(SB)
0x0057 00087 (z.go:14) ADDQ ,SP
0x005b 00091 (z.go:14) RET ,
但是无法检索这些结果。
引自Go Language specification: Go statements:
If the function has any return values, they are discarded when the function completes.
所以允许以 return 值作为 goroutines 执行函数 - 这没有任何问题,规范明确指出它们的 return 值被简单地丢弃,它不会导致任何错误,但你不会以通常的方式得到它(就像你直接调用函数一样)。
值被丢弃。 go
语句没有什么特别之处。你也可以这样写
...
_ = getNumber(i)
...
或者只是
...
getNumber(i)
...
甚至
与大多数其他编程语言不同,Go 例程不使用堆栈来存储结果和 return 地址。它有一个特殊的内存分配,用于在执行完成后自行销毁的内存。您可以在 Rob Pike(golang 的创始人)的演讲中看到有关它的详细信息。访问此 link 观看 YouTube 视频:https://www.youtube.com/watch?v=f6kdp27TYZs&index=4&list=LLRA7nvHOCb4nuU7byESOYIg
仅供参考:如果您尝试将函数结果分配给 var,如下所示:
res := go printNumber(i)
你会得到 语法错误,如下所示:
prog.go:4:7: syntax error: unexpected go, expecting expression
你可以看看here。
有人可以从 goroutine 中给出澄清值 return。来自 goroutine 的 returned 值是否存储在 stake 中。
示例:
// function getNumber returns the "int i" and we can't use this returned value
// because this function is invoked as goroutine.
// We know that, to communicate between main and goroutine one could
// use the channel ( chan <- i), but I am interested to know about
// the use of return i in goroutine. Is it possible to get/ use this
// returned value.
func getNumber(i int) int {
return i
}
func main() {
for i:=0; i<10; i++ {
go printNumber(i)
}
time.Sleep(5)
}
我们是否应该尽量避免在 go routine 中使用 return 值?
快速查看汇编输出表明
$ go build -gcflags -S z.go
getNumber()
函数确实将其结果存储到堆栈中
"".getNumber t=1 size=16 value=0 args=0x10 locals=0x0
0x0000 00000 (z.go:5) TEXT "".getNumber+0(SB),4,[=11=]-16
0x0000 00000 (z.go:6) MOVQ "".i+8(FP),BX
0x0005 00005 (z.go:6) MOVQ BX,"".~r1+16(FP)
0x000a 00010 (z.go:6) RET ,
所以当它被一个 goroutine 调用时,它会将它的结果存储到堆栈中。然而,这是一个新堆栈,在 goroutine 结束时被销毁,因此不可能检索 return 值。
"".main t=1 size=96 value=0 args=0x0 locals=0x18
0x0000 00000 (z.go:9) TEXT "".main+0(SB),-0
0x0000 00000 (z.go:9) MOVQ (TLS),CX
0x0009 00009 (z.go:9) CMPQ SP,16(CX)
0x000d 00013 (z.go:9) JHI ,22
0x000f 00015 (z.go:9) CALL ,runtime.morestack_noctxt(SB)
0x0014 00020 (z.go:9) JMP ,0
0x0016 00022 (z.go:9) SUBQ ,SP
0x001a 00026 (z.go:10) MOVQ [=12=],AX
0x001c 00028 (z.go:10) CMPQ AX,
0x0020 00032 (z.go:10) JGE [=12=],74
0x0022 00034 (z.go:11) MOVQ AX,"".i+16(SP)
0x0027 00039 (z.go:11) MOVQ AX,(SP)
0x002b 00043 (z.go:11) MOVQ $"".getNumber·f+0(SB),CX
0x0032 00050 (z.go:11) PUSHQ CX,
0x0033 00051 (z.go:11) PUSHQ ,
0x0035 00053 (z.go:11) PCDATA [=12=],[=12=]
0x0035 00053 (z.go:11) CALL ,runtime.newproc(SB)
0x003a 00058 (z.go:11) POPQ ,CX
0x003b 00059 (z.go:11) POPQ ,CX
0x003c 00060 (z.go:10) MOVQ "".i+16(SP),AX
0x0041 00065 (z.go:10) INCQ ,AX
0x0044 00068 (z.go:10) NOP ,
0x0044 00068 (z.go:10) CMPQ AX,
0x0048 00072 (z.go:10) JLT [=12=],34
0x004a 00074 (z.go:13) MOVQ ,(SP)
0x0052 00082 (z.go:13) PCDATA [=12=],[=12=]
0x0052 00082 (z.go:13) CALL ,time.Sleep(SB)
0x0057 00087 (z.go:14) ADDQ ,SP
0x005b 00091 (z.go:14) RET ,
但是无法检索这些结果。
引自Go Language specification: Go statements:
If the function has any return values, they are discarded when the function completes.
所以允许以 return 值作为 goroutines 执行函数 - 这没有任何问题,规范明确指出它们的 return 值被简单地丢弃,它不会导致任何错误,但你不会以通常的方式得到它(就像你直接调用函数一样)。
值被丢弃。 go
语句没有什么特别之处。你也可以这样写
...
_ = getNumber(i)
...
或者只是
...
getNumber(i)
...
甚至
与大多数其他编程语言不同,Go 例程不使用堆栈来存储结果和 return 地址。它有一个特殊的内存分配,用于在执行完成后自行销毁的内存。您可以在 Rob Pike(golang 的创始人)的演讲中看到有关它的详细信息。访问此 link 观看 YouTube 视频:https://www.youtube.com/watch?v=f6kdp27TYZs&index=4&list=LLRA7nvHOCb4nuU7byESOYIg
仅供参考:如果您尝试将函数结果分配给 var,如下所示:
res := go printNumber(i)
你会得到 语法错误,如下所示:
prog.go:4:7: syntax error: unexpected go, expecting expression
你可以看看here。