如何识别一个goroutine?

Ale*_*x B 6 go goroutine

假设我有一堆 goroutine 的堆栈跟踪,例如:

goroutine 5633 [select]:
net/http.(*persistConn).writeLoop(0xc21303ac00)
    /usr/lib/go/src/pkg/net/http/transport.go:791 +0x271
created by net/http.(*Transport).dialConn
    /usr/lib/go/src/pkg/net/http/transport.go:529 +0x61e
Run Code Online (Sandbox Code Playgroud)

在我的例子中,一个独特的特定于应用程序的对象由一组 goroutine 提供服务,我想查看与特定对象相关的 goroutine 的堆栈跟踪。我有数百个特定于应用程序的对象,所以我得到了数百个相同的 goroutine。

我将如何将我的日志与堆栈跟踪中的 goroutine 相关联?似乎没有一种方法可以在堆栈跟踪中识别当前 goroutine,也无法命名 goroutine,因此我可以在堆栈跟踪中看到特定值。

聚苯乙烯

我已经在 Go 邮件列表上阅读了相关的为什么你想要做的帖子,所以我正在寻找替代方案/黑客/解决方法(希望不涉及用日志散布代码每隔一行调用一次)。

小智 6

这个方法比 @Alex B 更简单。它使用 debug.Stack() 以字节切片形式返回堆栈跟踪的事实,其中包含 goroutine 它在第二个字边界中的 id 以及堆栈跟踪。并解析它。

package main

import (
    "bytes"
    "fmt"
    "runtime/debug"
    "sync"
)

func main() {
    w := sync.WaitGroup{}
    w.Add(1)
    go func() {
        gr := bytes.Fields(debug.Stack())[1]
        fmt.Println(string(gr))
        w.Done()
    }()
    w.Wait()
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*x B 5

一种解决方法是可能的,并且涉及一小段 C 代码。

goid.c

#include <runtime.h>
void ·GetGoID(int32 ret) {
    ret = g->goid;
    USED(&ret);
}
Run Code Online (Sandbox Code Playgroud)

main.go

package main
import (
    "fmt"
    "sync"
)
// Declaration is required
func GetGoID() int32
func main() {
    var wg sync.WaitGroup
    f := func() {
        wg.Add(1)
        go func() {
            fmt.Printf("goroutine %d\n", GetGoID())
            wg.Done()
        }()
    }
    for i := 0; i < 10; i++ {
        f()
    }
    wg.Wait()
}
Run Code Online (Sandbox Code Playgroud)

构建并运行

$ go build
$ ./example
goroutine 20
goroutine 21
goroutine 22
goroutine 23
goroutine 24
goroutine 25
goroutine 26
goroutine 27
goroutine 28
goroutine 29
Run Code Online (Sandbox Code Playgroud)