如何获取goroutineID

本文介绍了如何在Go语言中,尽管其并未直接提供协程ID,但通过修改源码、运行时栈、debug库和汇编等方法获取goroutineID,以及这些方法的优缺点,特别提到了与分布式锁的潜在应用.
摘要由CSDN通过智能技术生成

我们常用的C/C++,java等语言,原生的对ThreadID提供了访问的能力,但是Go语言并没有。线程ID可以与线程本地存储(TLS)搭配使用,可以产生一些新的玩法。线程ID可以用于分布式锁的条件,即让特定的线程对特定的资源上锁或解锁。

Go语言虽然未向外提供协程(Go语言本身的并发单元是协程)ID的获取方式。但并不代表它没有协程ID的概念,也不代表我们获取不到协程ID。
如下将提供几种获取goroutineID的办法。

方式1,修改Go源码,封装getg()
该方式对Go源码具有侵入性,不建议使用。该方式也不利于基础库相关组件的维护。

func GetGoID1() uint64 {
	return getg().goid
}

方式2,在运行时栈中查找
该方式打印与Copy运行时栈信息,会产生一定开销,速度有限,但对源码无侵入性。

func GetGoID2() int64 {
	b := make([]byte, 64)
	b = b[:runtime.Stack(b, false)]
	var id int64
	fmt.Sscanf(string(b), "goroutine %d", &id)
	return id
}

方式3,通过debug库获取栈信息,同时扫描goroutineID,该方式弊端同方式2

func GetGoID3() uint64 {
	stack := debug.Stack()
	var id uint64
	fmt.Sscanf(string(stack[:64]), "goroutine %d", &id)
	return id
}

方式4,采用Go汇编的方式
此方式是根据GMP模型中g结构的字段偏移,获取goroutineID。

// 通过汇编指令,映射出goid,见曹春晖的分享
// copy from https://github.com/cch123/goroutineid

var offsetDict = map[string]int64{
	"go1.4":  128,
	"go1.5":  184,
	"go1.6":  192,
	"go1.7":  192,
	"go1.8":  192,
	"go1.9":  152,
	"go1.10": 152,
	"go1.11": 152,
	"go1.12": 152,
	"go1.13": 152,
	"go1.14": 152,
	//...
	"go1.20": 152,
}

var offset = func() int64 {
	ver := strings.Join(strings.Split(runtime.Version(), ".")[:2], ".")
	return offsetDict[ver]
}()

// GetGoID returns the goroutine id
func GetGoID4() int64

go_tls.h

#ifdef GOARCH_arm
#define LR R14
#endif

#ifdef GOARCH_amd64
#define	get_tls(r)	MOVQ TLS, r
#define	g(r)	0(r)(TLS*1)
#endif

#ifdef GOARCH_amd64p32
#define	get_tls(r)	MOVL TLS, r
#define	g(r)	0(r)(TLS*1)
#endif

#ifdef GOARCH_386
#define	get_tls(r)	MOVL TLS, r
#define	g(r)	0(r)(TLS*1)
#endif

goid.s

#include "textflag.h"
#include "go_tls.h"

// func GetGoID4() int64
TEXT ·GetGoID4(SB), NOSPLIT, $0-8
	get_tls(CX)
	MOVQ g(CX), AX
	MOVQ ·offset(SB), BX
	LEAQ 0(AX)(BX*1), DX
	MOVQ (DX), AX
	MOVQ AX, ret+0(FP)
	RET

Reference
1.https://github.com/cch123/asmshare/blob/master/layout.md

2.https://www.bilibili.com/video/BV1Xb411J7Yk/?spm_id_from=333.337.search-card.all.click&vd_source=1333bbca93d420260aa7e0f7e45af54a

3.https://chai2010.cn/advanced-go-programming-book/ch3-asm/ch3-01-basic.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值