官方不推薦使用 Goroutine ID,但它自己卻使用:原來是這麼做的

在操作系統中,每個進程都會有一個唯一的進程編號,每個線程也有自己唯一的線程編號。同樣在 Go 語言中,每個 Goroutine 也有自己唯一的 Go 程編號(下文簡稱為 goid),這個編號在 panic 等場景下經常遇到。雖然 Goroutine 有內在的編號,但是 Go 語言卻刻意沒有提供獲取該編號的接口。

故意設計沒有 goid

根據官方的相關資料顯示,Go 語言刻意沒有提供 goid 的原因是為了避免被濫用。因為大部分用戶在輕鬆拿到 goid 之後,在之後的編程中會不自覺地編寫出強依賴 goid 的代碼。強依賴 goid 將導致這些代碼不好移植,同時也會導致併發模型複雜化。同時,Go 語言中可能同時存在海量的 Goroutine,但是每個 Goroutine 何時被銷燬並不好實時監控,這也會導致依賴 goid 的資源無法很好地自動回收(需要手工回收)。

如何獲取 goid

然而似乎獲取 goid 的場景很多?搜索 goroutine id,你看,教你獲取 goid 的方法真不少:

官方不推薦使用 Goroutine ID,但它自己卻使用:原來是這麼做的

本文提供的方法來自標準庫。

<code>var goroutineSpace = []byte("goroutine ")

func curGoroutineID() uint64 {
\tbp := littleBuf.Get().(*[]byte)
\tdefer littleBuf.Put(bp)
\tb := *bp
\tb = b[:runtime.Stack(b, false)]
\t// Parse the 4707 out of "goroutine 4707 ["
\tb = bytes.TrimPrefix(b, goroutineSpace)
\ti := bytes.IndexByte(b, ' ')
\tif i < 0 {
\t\tpanic(fmt.Sprintf("No space found in %q", b))
\t}
\tb = b[:i]
\tn, err := parseUintBytes(b, 10, 64)
\tif err != nil {
\t\tpanic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
\t}
\treturn n
}/<code>

代碼位於:https://github.com/golang/net/blob/master/http2/gotrack.go#L51,是 HTTP2 使用的。如果你真的特殊場景需要 goid,可以試試將這裡相關代碼拷貝一份使用。

當然,咱們儘量還是遵循官方標準,不去依賴 goid 哦。


分享到:


相關文章: