【问题标题】:How can I get a goroutine's runtime ID?如何获取 goroutine 的运行时 ID?
【发布时间】:2023-02-09 15:16:22
【问题描述】:

如何获取 goroutine 的运行时 ID?

我从一个导入的包中获取交错日志——一种方法是向每个 goroutine 的日志添加一个唯一标识符。

我发现了一些对runtime.GoID的引用:

func worker() {
    id := runtime.GoID()
    log.Println("Goroutine ID:", id)
}

但看起来这已经过时/已被删除 - https://pkg.go.dev/runtime

【问题讨论】:

  • 从来没有 goroutine 范围标识符。您必须将需要的任何本地上下文传递给 goroutine

标签: go logging concurrency runtime


【解决方案1】:

Go 故意选择不提供 ID,因为它会鼓励更糟糕的软件并损害整个生态系统:https://go.dev/doc/faq#no_goroutine_id

通常,去匿名化 goroutines 的愿望是一个设计缺陷,强烈不推荐。几乎总会有更好的方法来解决手头的问题。例如,如果你需要一个唯一的标识符,它应该被传递到函数中或者可能通过 context.Context 传递。

但是,运行时在内部需要实现的 ID。出于教育目的,您可以通过以下方式找到它们:

package main

import (
    "bytes"
    "errors"
    "fmt"
    "runtime"
    "strconv"
)

func main() {
    fmt.Println(goid())

    done := make(chan struct{})
    go func() {
        fmt.Println(goid())
        done <- struct{}{}
    }()
    go func() {
        fmt.Println(goid())
        done <- struct{}{}
    }()
    <-done
    <-done
}

var (
    goroutinePrefix = []byte("goroutine ")
    errBadStack     = errors.New("invalid runtime.Stack output")
)

// This is terrible, slow, and should never be used.
func goid() (int, error) {
    buf := make([]byte, 32)
    n := runtime.Stack(buf, false)
    buf = buf[:n]
    // goroutine 1 [running]: ...

    buf, ok := bytes.CutPrefix(buf, goroutinePrefix)
    if !ok {
        return 0, errBadStack
    }

    i := bytes.IndexByte(buf, ' ')
    if i < 0 {
        return 0, errBadStack
    }

    return strconv.Atoi(string(buf[:i]))
}

示例输出:

1 <nil>
19 <nil>
18 <nil>

通过访问 g 结构中的 goid 字段,也可以通过程序集找到它们(不太便携)。这就是像github.com/petermattis/goid 这样的软件包通常的做法。

【讨论】:

    【解决方案2】:

    您需要通过运行时包函数访问它。这是一个例子:

    import (
        "fmt"
        "runtime"
    )
    
    func worker() {
        var buf [64]byte
        n := runtime.Stack(buf[:], false)
        id := fmt.Sprintf("%x", buf[:n])
        log.Println("Goroutine ID:", id)
    }
    

    在此示例中,对 runtime.Stack 的调用返回当前 goroutine 的堆栈跟踪,其中包括其唯一标识符。通过将其格式化为十六进制字符串,您可以获得可在日志中使用的标识符的紧凑表示。

    【讨论】:

      猜你喜欢
      • 2022-11-13
      • 2021-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-02
      • 2019-11-24
      相关资源
      最近更新 更多