go没有go协程号(goroutineid)

kingstarer · 2020-04-28 14:56:13 · 3079 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2020-04-28 14:56:13 的主题,其中的信息可能已经有所发展或是发生改变。

20200428

go没有go协程号(goroutineid)


今天想给日志添加一个前缀,以区分不同goroutine的日志,方便以后做日志跟踪。最直接的想法是在日志函数里面增加打印goroutineid,跟以前用c语言在日志打印线程id/进程id一样。

但是网上查了一下,go开发中不建议使用goroutineid,也没有提供获取协程id的函数(旧版本有,但现在已删除)

原因是担心人们使用goroutineid构建协程私有存储,这样很容易导致协程资源一直被占用,无法正常被gc回收。

(协程结束了,但是协程引用的变量还存放在用户自己构造的协程级私有存储,这时gc无法回收协程)

如果想在日志里面输出traceid,官方建议使用context包。但是这样做要求每个函数都增加context参数,在程序运行过程中层层传递,才可以实现。这样即不现实,也不优雅。

为了解决goroutineid,网上各出奇招,有的使用runtime包未公开的方法获取:

func Goid() int {
    defer func()  {
        if err := recover(); err != nil {
            fmt.Println("panic recover:panic info:%v", err)        }
    }()

    var buf [64]byte
    n := runtime.Stack(buf[:], false)
    idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
    id, err := strconv.Atoi(idField)
    if err != nil {
        panic(fmt.Sprintf("cannot get goroutine id: %v", err))
    }
    return id
}

这个方法我觉得靠谱,显然runtime包是肯定有获取协程id的方法的,因为处理panic时默认会输出问题协程号。但是这样做效率会不会有问题,暂时还不清楚。

另外有人使用汇编,cgo的方法获取协程号的,例如github的包:github.com/petermattis/goid

这种效率应该高一些,网上有人测试说差了1000倍,不过这种方法兼容性不好,几乎每个版本都要使用不同的方法。


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3079 次点击  
加入收藏 微博
2 回复  |  直到 2024-05-06 12:16:22
jthmath
jthmath · #1 · 5年之前

似乎没什么场景真的需要goroutine号

jiangguilong2000
jiangguilong2000 · #2 · 11月之前

有需要的,特别是排查并发的问题时,通过日志里打印goroutine ID ,可以帮助排查

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传