A high-performance Go package for retrieving the current goroutine ID using optimized assembly implementations for Go 1.23-1.25 on amd64/arm64, with automatic fallback to a stack trace method for maximum compatibility.
- Optimized for Go 1.23, 1.24, and 1.25 on amd64 and arm64 architectures
- Future-proofed: Automatic fallback to stack trace method for newer and older Go versions or unsupported architectures
- Universal compatibility: Works on all Go versions and architectures (via slower fallback for unsupported versions)
The Go team explicitly discourages accessing goroutine IDs in production code. Goroutine IDs are considered internal implementation details and should not be relied upon for application logic. The Go runtime intentionally does not expose goroutine IDs through its public API.
This library was specifically created for and maintained by Outrig - a dev time observability tool for Go servers. It's appropriate for debugging, development tools, profiling, and observability systems where understanding goroutine behavior is essential.
You've been warned - now feel free to use it responsibly! 😄
- High-performance: Direct assembly access to goroutine ID on Go 1.23-1.25 (amd64/arm64)
- Automatic fallback: Stack trace method for all other Go versions or architectures
- Future-proofed: Graceful degradation for newer Go versions until optimizations are added
- Zero dependencies: Pure Go implementation with no external dependencies
go get github.com/outrigdev/goidpackage main
import (
"fmt"
"github.com/outrigdev/goid"
)
func main() {
// Get the current goroutine ID
id := goid.Get()
fmt.Printf("Current goroutine ID: %d\n", id)
// Force use of stack trace method (for comparison)
id2 := goid.GetFromStack()
fmt.Printf("Goroutine ID from stack: %d\n", id2)
}Returns the current goroutine ID using the fastest available method:
- On Go 1.23-1.25 with amd64/arm64: Uses optimized assembly implementation
- On other versions/architectures: Falls back to stack trace method
Returns the current goroutine ID by parsing the stack trace. This is the fallback method used when the optimized assembly implementation is not available.
Benchmark results on Apple M3 Pro (Go 1.24, darwin/arm64):
goos: darwin
goarch: arm64
pkg: github.com/outrigdev/goid
cpu: Apple M3 Pro
BenchmarkGet
BenchmarkGet-12 879633932 1.306 ns/op
BenchmarkGetFromStack
BenchmarkGetFromStack-12 749905 1561 ns/op
The optimized Get() function is approximately 1000x+ faster than the stack trace method, demonstrating the significant performance benefit of the assembly optimization.
This substantial speed-up is particularly beneficial for debugging, tracing, logging, or other scenarios where retrieving goroutine IDs frequently occurs.
For comprehensive testing and performance results across GitHub Actions runner platforms:
- Test Results - Correctness testing across available GitHub runner platforms and Go versions
- Benchmark Results - Performance benchmarks across available GitHub runner platforms and Go versions
- Go 1.23, 1.24, 1.25 on amd64 architecture
- Go 1.23, 1.24, 1.25 on arm64 architecture
- All Go versions on all architectures
- Automatically used when assembly implementation is not available
The package uses build constraints to select the appropriate implementation:
- Assembly Method: Directly accesses the goroutine structure in memory using assembly code to read the
goidfield - Stack Trace Method: Parses the first line of
runtime.Stack()output to extract the goroutine ID using optimized string parsing (regexp-free for better performance)
The assembly method is significantly faster but requires knowledge of the internal Go runtime structures, which can change between Go versions. The stack trace method is slower but works across all Go versions.
For the optimized assembly implementation, this package includes exact copies of the internal g (goroutine) struct definitions from the Go runtime source code for each supported version:
- Go 1.23: Complete
gstruct with 161 lines including all fields likegoid,stack,atomicstatus, etc. - Go 1.24: Updated
gstruct with additional fields likefipsIndicatorandsyncGroup
Critical: Version-Locked Compatibility
This package uses Go build constraints to version-lock each struct definition to its corresponding Go release. This is essential because the internal g struct layout can change between Go versions, and accessing the wrong memory offset would cause crashes or incorrect results.
Many other goroutine ID libraries attempt to use these internal structures but fail to properly version-lock them, leading to compatibility issues when Go releases update the runtime internals. This package solves that problem by:
- Exact struct copies: Each struct is an exact copy from the corresponding Go runtime source
- Build constraints:
//go:build go1.23 && !go1.24ensures each struct is only used with its intended Go version - Automatic fallback: When the optimized version isn't available, the package automatically uses the universal stack trace method
The assembly functions (getg()) retrieve the current goroutine pointer, and the Go code then accesses the goid field directly from the version-matched struct, ensuring both safety and performance.
| Go Version | Architecture | getg() Assembly | Optimized | Implementation |
|---|---|---|---|---|
| pre-1.23 | all | ❌ | ❌ | Stack trace fallback |
| 1.23 | amd64 | ✅ | ✅ | Assembly + struct access |
| 1.23 | arm64 | ✅ | ✅ | Assembly + struct access |
| 1.23 | other | ❌ | ❌ | Stack trace fallback |
| 1.24 | amd64 | ✅ | ✅ | Assembly + struct access |
| 1.24 | arm64 | ✅ | ✅ | Assembly + struct access |
| 1.24 | other | ❌ | ❌ | Stack trace fallback |
| 1.25 | amd64 | ✅ | ✅ | Assembly + struct access |
| 1.25 | arm64 | ✅ | ✅ | Assembly + struct access |
| 1.25 | other | ❌ | ❌ | Stack trace fallback |
| 1.26+ | all | ❌ | ❌ | Stack trace fallback |
Apache-2.0
Copyright 2025, Command Line Inc.