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

将函数作为 go 例程调用会产生与 go 例程不同的调用堆栈,作为匿名 func

将函数作为 go 例程调用会产生与 go 例程不同的调用堆栈,作为匿名 func

Go
翻翻过去那场雪 2022-08-01 11:10:16
我有一个名为PrintCaller()的函数,它调用运行时。Caller() 并跳过一帧以获取和打印调用方(PrintCaller 的)文件名和行号。当同步运行时,如果作为匿名函数调用异步,则按预期工作。但是,如果仅使用关键字运行,则调用方的堆栈帧将替换为某些内部函数调用。go例如,这是函数:func printCaller(wait chan bool) {    _, fileName, line, _ := runtime.Caller(1)    fmt.Printf("Filename: %s, line: %d\n", fileName, line)}如果我打电话是这样的:func main() {    printCaller()    go func(){printCaller()}()    go printCaller()}输出为:Filename: /tmp/sandbox297971268/prog.go, line: 19Filename: /tmp/sandbox297971268/prog.go, line: 22Filename: /usr/local/go-faketime/src/runtime/asm_amd64.s, line: 1374此处的工作示例:https://play.golang.org/p/Jv21SVDY2Ln为什么当我打电话时会发生这种情况,而当我打电话时却不会发生这种情况?另外,有没有办法使用?go PrintCaller()go func(){PrintCaller()}()go PrintCaller()
查看完整描述

1 回答

?
holdtom

TA贡献1805条经验 获得超10个赞

您看到的输出是人们所期望的,考虑到Go运行时系统的内部工作原理:


一个 goroutine,例如在包中调用你自己的主函数,但也包括 由 启动的例程,实际上是从一些特定于机器的启动例程调用的。在操场上,那是.mainmaingo somefunc()src/runtime/asm_amd64.s


定义闭包时,例如:


f := func() {

    // code

}

这将创建一个匿名函数。称呼它:


f()

从调用方所在的任何位置调用该匿名函数。无论闭包是分配给变量(如上所示),还是立即调用,或者稍后使用 ,或者其他什么,都是如此:fdefer


defer func() {

    // code ...

}()

所以,写:


go func() {

    // code ...

}()

只需从同一个特定于计算机的启动调用此处的匿名函数即可。如果该函数随后调用您的函数(该函数用于跳过函数并查找其调用方),它将找到匿名函数:printCallerruntime.Caller(1)printCaller


Filename: /tmp/sandbox297971268/prog.go, line: 22

例如。


但是当你写:


go printCaller()

您正在调用从特定于计算机的 goroutine 启动代码命名的函数。printCaller


由于打印其调用方的名称(即此特定于计算机的启动代码),因此这就是您所看到的。printCaller


这里有一个很大的警告,那就是允许失败。这就是为什么它返回一个布尔值和值。无法保证可以找到特定于计算机的程序集调用方。runtime.Callerokpc uintptr, file string, line int


查看完整回答
反对 回复 2022-08-01
  • 1 回答
  • 0 关注
  • 89 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信