如何识别 goroutine?

huangapple go评论87阅读模式
英文:

How to identify a 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

在我的情况下,一组goroutine为一个唯一的应用程序特定对象提供服务,我想查看与特定对象相关的goroutine的堆栈跟踪。我有数百个应用程序特定对象,所以我会得到数百个相同的goroutine。

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

PS

我已经阅读了Go邮件列表上相关的帖子,了解了为什么要这样做,所以我正在寻找替代方案/技巧/变通方法(希望不需要在代码中频繁添加日志调用)。

英文:

Let's say I have a stacktrace for a bunch of goroutines, e. g.:

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

In my case a unique application-specific object is served by a set of goroutines, and I want to look at the stacktrace of goroutines relating to a particular object. I have hundreds of application-specific objects, so I get hundreds of identical goroutines.

How would I go about correlating my logs with goroutines in the stacktrace? There doesn't seem to be a way of identifying a current goroutine in a stack trace and no way of naming a goroutine so I can see a specific value in stack trace.

PS

I've already read the related why-would-you-want-to-do-it posts on Go mailing list, so I'm looking for alternatives/hacks/workarounds (that hopefully don't involve sprinkling the code with a log call every other line).

答案1

得分: 5

这是一个比@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()
}
英文:

Play

This method is simpler than @Alex B. It use the fact that debug.Stack() return stack trace in the form of byte slice which contains goroutine its id in the second word boundary along with, well stack trace. And parse it.

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()
}

答案2

得分: 4

一个解决方法是可能的,它涉及一小段C代码。

goid.c

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

main.go

package main
import (
    "fmt"
    "sync"
)
// 声明是必需的
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()
}

构建和运行

$ go build
$ ./example
goroutine 20
goroutine 21
goroutine 22
goroutine 23
goroutine 24
goroutine 25
goroutine 26
goroutine 27
goroutine 28
goroutine 29
英文:

A workaround is possible, and involves a small piece of C code.

goid.c

#include &lt;runtime.h&gt;
void &#183;GetGoID(int32 ret) {
	ret = g-&gt;goid;
	USED(&amp;ret);
}

main.go

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

Build and run

$ go build
$ ./example
goroutine 20
goroutine 21
goroutine 22
goroutine 23
goroutine 24
goroutine 25
goroutine 26
goroutine 27
goroutine 28
goroutine 29

huangapple
  • 本文由 发表于 2014年10月14日 00:34:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/26344750.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定