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

我有一个名为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: 19

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

Filename: /usr/local/go-faketime/src/runtime/asm_amd64.s, line: 1374

此处的工作示例:https://play.golang.org/p/Jv21SVDY2Ln


为什么当我打电话时会发生这种情况,而当我打电话时却不会发生这种情况?另外,有没有办法使用?go PrintCaller()go func(){PrintCaller()}()go PrintCaller()


翻翻过去那场雪
浏览 91回答 1
1回答

holdtom

您看到的输出是人们所期望的,考虑到Go运行时系统的内部工作原理:一个 goroutine,例如在包中调用你自己的主函数,但也包括 由 启动的例程,实际上是从一些特定于机器的启动例程调用的。在操场上,那是.mainmaingo somefunc()src/runtime/asm_amd64.s定义闭包时,例如:f := func() {    // code}这将创建一个匿名函数。称呼它:f()从调用方所在的任何位置调用该匿名函数。无论闭包是分配给变量(如上所示),还是立即调用,或者稍后使用 ,或者其他什么,都是如此:fdeferdefer func() {    // code ...}()所以,写:go func() {    // code ...}()只需从同一个特定于计算机的启动调用此处的匿名函数即可。如果该函数随后调用您的函数(该函数用于跳过函数并查找其调用方),它将找到匿名函数:printCallerruntime.Caller(1)printCallerFilename: /tmp/sandbox297971268/prog.go, line: 22例如。但是当你写:go printCaller()您正在调用从特定于计算机的 goroutine 启动代码命名的函数。printCaller由于打印其调用方的名称(即此特定于计算机的启动代码),因此这就是您所看到的。printCaller这里有一个很大的警告,那就是允许失败。这就是为什么它返回一个布尔值和值。无法保证可以找到特定于计算机的程序集调用方。runtime.Callerokpc uintptr, file string, line int
打开App,查看更多内容
随时随地看视频慕课网APP