English | 中文
A Go library for efficiently obtaining Goroutine ID by directly accessing the goroutine structure pointer (getg) through assembly.
- 🚀 High Performance: Directly access goroutine structure through assembly, avoiding
runtime.Stackcalls - 🔧 Multi-architecture Support: Supports x86, ARM, MIPS, PowerPC, RISC-V, and other CPU architectures
- 🛡️ Safe and Reliable: Dynamically calibrates offset to ensure compatibility across different Go versions
- 📦 Easy to Use: Provides a simple API interface
- ⚡ Zero Dependencies: Pure Go implementation with no external dependencies
In Go, obtaining the current goroutine ID typically requires parsing stack information through runtime.Stack, which has poor performance. This project directly accesses the goroutine structure pointer through assembly and reads the goroutine ID from the structure, resulting in significant performance improvement.
go get github.com/MegaXChan/faster-goroutine-idpackage main
import (
"fmt"
"sync"
goid "github.com/MegaXChan/faster-goroutine-id"
)
func main() {
wait := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wait.Add(1)
go func(v int) {
id := goid.GoroutineId()
fmt.Printf("index: %v, goroutine id: %v\n", v, id)
defer wait.Done()
}(i)
}
wait.Wait()
}package faster_goroutine_id
import (
"fmt"
"testing"
"time"
s "github.com/MegaXChan/faster-goroutine-id/internal"
)
func TestPerformance(t *testing.T) {
// Using this library
start1 := time.Now().UnixNano()
id1 := GoroutineId()
elapsed1 := time.Now().UnixNano() - start1
// Using traditional method
start2 := time.Now().UnixNano()
id2 := s.Gid()
elapsed2 := time.Now().UnixNano() - start2
fmt.Printf("faster-goroutine-id: ID=%d, time=%v ns\n", id1, elapsed1)
fmt.Printf("traditional method: ID=%d, time=%v ns\n", id2, elapsed2)
}- Get goroutine structure pointer: Directly obtain the current goroutine's
gstructure pointer through assembly instructions - Dynamic offset calibration: Dynamically calculate the offset of goroutine ID in the
gstructure during initialization - Read goroutine ID: Directly read the goroutine ID through pointer and offset
Provides corresponding assembly implementations for different CPU architectures:
getg_amd64.s: x86-64 architecturegetg_arm64.s: ARM64 architecturegetg_386.s: x86 architecturegetg_arm.s: ARM architecturegetg_ppc64.s: PowerPC 64-bit architecturegetg_riscv64.s: RISC-V 64-bit architecture- And other architecture support
Since the layout of the g structure may vary across different Go versions, this project dynamically calibrates the goroutine ID offset during initialization:
func calibrateOffset() {
// Verify offset accuracy in multiple goroutines
// Use majority voting algorithm to determine the correct offset
}- Operating Systems: Linux, Windows, macOS
- Architectures:
- x86: amd64, 386
- ARM: arm64, arm (v6, v7)
- MIPS: mips, mips64
- PowerPC: ppc64, ppc64le
- RISC-V: riscv64
- s390x
According to test results, using this library significantly improves performance for obtaining goroutine ID compared to traditional methods:
- Traditional method (
runtime.Stack): ~1000-2000 ns - This library: ~10-50 ns
Performance improvement is approximately 20-100x.
- Go Version Compatibility: Due to dependency on goroutine structure internal layout, different Go versions may require re-calibration of offset
- Platform Limitations: Only supports CPU architectures with implemented assembly
- Production Environment: Recommended to conduct thorough testing in critical paths
Issues and Pull Requests are welcome!
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Create a Pull Request
This project is open source under the MIT License. See the LICENSE file for details.
MegaXChan
- Thanks to the Go language community
- Thanks to all contributors
Tip: If you encounter any issues, please check Issues first or create a new issue.