via: http://blog.sgmansfield.com/2015/12/goroutine-ids/
作者:Scott Mansfield
獲取 Goroutine ID
Goroutine ID 真實存在嗎?
當然存在。
Go 運行時一定有某種方式來跟蹤 goroutine ID。
那我該使用它們嗎?
不該。
- 原因一:https://groups.google.com/forum/#!topic/golang-nuts/Nt0hVV_nqHE
- 原因二:https://groups.google.com/forum/#!topic/golang-nuts/0HGyCOrhuuI
- 原因三:http://stackoverflow.com/questions/19115273/looking-for-a-call-or-thread-id-to-use-for-logging
有沒有哪些包是我可以使用的?
已有的來自 Go Team 成員的包,被評價爲“用此包者,將入地獄。”
也有一些包基於 goroutine id 來建立 goroutine local storage,如:
- github.com/jtolds/gls
- github.com/tylerb/gls
但都有悖於 GO 語言的設計原則。
最簡代碼
如果讀到這裏,你仍“執迷不悟”,那麼下面就將展示如何獲取當前的 goroutine id :
Go 源碼中的駭客(Hacky)代碼
下列代碼源於 Brad Fitzpatrick 的 http/2
庫。它被整合進了 Go 1.6 中,僅僅被用於調試而非常規開發。
package main
import (
"bytes"
"fmt"
"runtime"
"strconv"
)
func main() {
fmt.Println(getGID())
}
func getGID() uint64 {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return n
}
工作原理解釋
通過解析調試信息來獲取 goroutine id 是可行的. http/2
庫就使用調試性的代碼來對連接進行追蹤查看。但僅僅是將 goroutine id 用於調試而已。
調試信息可以通過調用 runtime.Stack(buf []byte, all bool) int
來獲取,它會以文本形式打印堆棧信息到緩衝區中。堆棧信息的第一行會是如下文本: “goroutine #### […”
這裏的 #### 就是真實的 goroutine id. 剩餘代碼不過是進行一些文本操作來提取和解析堆棧信息中的數字。
CGo 版本對應的合法代碼
C 版本的代碼來自 github.com/davecheney/junk/id (譯者注:源鏈接失效,請訪問github.com/davecheney/junk/tree/master/id)。代碼中直接獲取了當前 goroutine 的 goid 屬性並返回它的值。
文件名: id.c
#include "runtime.h"
int64 ·Id(void) {
return g->goid;
}
文件名: id.go
package id
func Id() int64
我該怎麼做?
遠離 goroutine id 吧,並忘記它們的存在。從 GO 語言設計的角度來看,使用它們是危險的。因爲幾乎所有使用的目的都是去做一些和 goroutine-local 相關的事情。
而這違反了 Go 語言編程的“Share Memory By Communicating”原則。