douzhuican0041 2017-03-09 10:20
浏览 51
已采纳

如何通过运行时获取真实的文件名。在不同的goroutine中由匿名函数调用的调用者

I have this example code https://play.golang.org/p/c_2GECIcrW
What I expect getFileName will print out something like main.go:11 but what I get is the asm_amd64p32.s:1014

What can I do to get the expect result in this case?
Can I archive that and still using anonymous function?

  • 写回答

1条回答 默认 最新

  • ds122455 2017-03-18 22:17
    关注

    Your expectation is incorrect.

    Let me paste your code here for ease of explanation:

    package main
    
    import (
        "fmt"
        "path/filepath"
        "runtime"
        "time"
    )
    
    func main() {
        getFileName(1)
        time.Sleep(time.Hour)
    }
    
    func getFileName(shift int) {
        go func() {
            _, file, line, ok := runtime.Caller(shift)
            if !ok {
                file = "???"
                line = 0
            } else {
                file = filepath.Base(file)
            }
    
            fmt.Printf("%s:%d", file, line)
        }()
    }
    

    Your anonymous function is running in a goroutine spawned by getFileName.

    Each goroutine executes using its own call stack, even the goroutine spawned by getFileName starts with a fresh stack.

    By invoking runtime.Caller(skip int) with a skip value greater than zero, you can walk through the stack frames of the current goroutine.

    In your example:

    • runtime.Caller(0) prints main.go:17 because this is the line where runtime.Caller() is actually called,
    • runtime.Caller(1) prints asm_amd64p32.s:1014 because it is the top of the stack of the current goroutine,
    • runtime.Caller(x) for any x > 1 returns with the boolean ok set to false because you're trying to access memory above the top of the stack.

    If you're wondering what asm_amd64p32.s:1014 represents, actually it corresponds to the goexit assembly function of Go 1.8 (the Go Playground runs with the latest stable release of Go). Despite its name, the goexit function is always at the top of a goroutine stack: it invokes the goroutine entry point function and then clean up the stack after the function returns. The goexit implementation is architecture-specific, as it is most of the code that handles the details of the goroutines stack.

    Back to your question, you cannot expect to see main.go:11 mentioned in the stacktrace of the goroutine spawned by getFileName, because the main function is not in the stack at all. Don't spawn a goroutine, if you really need to print the stacktrace of the main function.

    Having said that, there is something more to mention. The Go runtime actually stores additional information about where a goroutine has been spawned. The debug.PrintStack() function (which is in turn based on runtime.Stack()) is able to print it out in a nicely formatted stacktrace:

    package main
    
    import (
        "time"
        "runtime/debug"
    )
    
    func main() {
        getFileName(1)
        time.Sleep(time.Hour)
    }
    
    func getFileName(shift int) {
        go func() {
            debug.PrintStack()
        }()
    }
    

    Output:

    goroutine 5 [running]:
    runtime/debug.Stack(0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/runtime/debug/stack.go:24 +0x80
    runtime/debug.PrintStack()
        /usr/local/go/src/runtime/debug/stack.go:16 +0x20
    main.getFileName.func1()
        /tmp/sandbox085104368/main.go:15 +0x20
    created by main.getFileName
        /tmp/sandbox085104368/main.go:16 +0x40
    

    Being all these details implementation-dependent and subject to change between different Go releases, there is - by design - no easy way to access them via the standard library. They're provided for debugging purposes and you, as a developer, should not rely on these information.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler