协程G 底层实现
go
type g struct {
// Stack parameters.
stack stack // offset known to runtime/cgo
stackguard0 uintptr // offset known to liblink
stackguard1 uintptr // offset known to liblink
_panic *_panic // innermost panic - offset known to liblink
_defer *_defer // innermost defer
m *m // current m; offset known to arm liblink
sched gobuf
syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
syscallbp uintptr // if status==Gsyscall, syscallbp = sched.bp to use in fpTraceback
stktopsp uintptr // expected sp at top of stack, to check in traceback
param unsafe.Pointer
atomicstatus atomic.Uint32
stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
goid uint64
// ... 其他参数
获取go协程的ID
- 获取当前运行的G getg()
go
// getg returns the pointer to the current g.
// The compiler rewrites calls to this function into instructions
// that fetch the g directly (from TLS or from the dedicated register).
func getg() *g
- 根据goid字段的偏移量 得到ID
go
goidOffset := xxxx
// GoID returns the goroutine id of current goroutine
func GoID() int64 {
g := getg()
p_goid := (*int64)(unsafe.Pointer(g + goidOffset))
return *p_goid
}
//go:linkname getg runtime.getg
func getg() uintptr
不同版本的go实现 goid字段的偏移可能不同 可以使用开源库获取 runtime路径下g结构体 然后获取goid的偏移量
go
// github.com/modern-go/reflect2/type_map.go
// offset for go1.4
var goidOffset uintptr = 128
func init() {
// TypeByName return the type by its name, just like Class.forName in java
gType := reflect2.TypeByName("runtime.g").(reflect2.StructType)
if gType == nil {
panic("failed to get runtime.g type")
}
goidField := gType.FieldByName("goid")
goidOffset = goidField.Offset()
}
获取go协程的ID有啥用?
可以实现 Goroutine-Local-Storage cloudwego/localsession实现