| name | go-optimization |
| description | Performance optimization techniques including profiling, memory management, benchmarking, and runtime tuning. Use when optimizing Go code performance, reducing memory usage, or analyzing bottlenecks. |
Go Optimization Skill
This skill provides expert guidance on Go performance optimization, covering profiling, benchmarking, memory management, and runtime tuning for building high-performance applications.
When to Use
Activate this skill when:
- Profiling application performance
- Optimizing CPU-intensive operations
- Reducing memory allocations
- Tuning garbage collection
- Writing benchmarks
- Analyzing performance bottlenecks
- Optimizing hot paths
- Reducing lock contention
Profiling
CPU Profiling
import (
"os"
"runtime/pprof"
)
func main() {
f, err := os.Create("cpu.prof")
if err != nil {
log.Fatal(err)
}
defer f.Close()
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
runApplication()
}
Memory Profiling
import (
"os"
"runtime"
"runtime/pprof"
)
func writeMemProfile(filename string) {
f, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
defer f.Close()
runtime.GC()
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal(err)
}
}
HTTP Profiling
import (
_ "net/http/pprof"
"net/http"
)
func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
runServer()
}
Execution Tracing
import (
"os"
"runtime/trace"
)
func main() {
f, err := os.Create("trace.out")
if err != nil {
log.Fatal(err)
}
defer f.Close()
if err := trace.Start(f); err != nil {
log.Fatal(err)
}
defer trace.Stop()
runApplication()
}
Benchmarking
Basic Benchmarks
func BenchmarkStringConcat(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = "hello" + " " + "world"
}
}
func BenchmarkStringBuilder(b *testing.B) {
for i := 0; i < b.N; i++ {
var sb strings.Builder
sb.WriteString("hello")
sb.WriteString(" ")
sb.WriteString("world")
_ = sb.String()
}
}
Sub-benchmarks
func BenchmarkEncode(b *testing.B) {
data := generateTestData()
b.Run("JSON", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
json.Marshal(data)
}
})
b.Run("MessagePack", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
msgpack.Marshal(data)
}
})
}
Parallel Benchmarks
func BenchmarkConcurrentAccess(b *testing.B) {
cache := NewCache()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
cache.Get("key")
}
})
}
Benchmark Comparison
go test -bench=. -benchmem > old.txt
go test -bench=. -benchmem > new.txt
benchstat old.txt new.txt
Memory Optimization
Escape Analysis
func stackAlloc() int {
x := 42
return x
}
func heapEscape() *int {
x := 42
return &x
}
func noAlloc(w io.Writer, data []byte) {
w.Write(data)
}
func withAlloc() io.Writer {
var b bytes.Buffer
return &b
}
Pre-allocation
func badAppend(n int) []int {
var result []int
for i := 0; i < n; i++ {
result = append(result, i)
}
return result
}
func goodAppend(n int) []int {
result := make([]int, 0, n)
for i := 0; i < n; i++ {
result = append(result, i)
}
return result
}
func knownLength(n int) []int {
result := make([]int, n)
for i := 0; i < n; i++ {
result[i] = i
}
return result
}
func badConcat(strs []string) string {
result := ""
for _, s := range strs {
result += s
}
return result
}
func goodConcat(strs []string) string {
var sb strings.Builder
sb.Grow(estimateSize(strs))
for _, s := range strs {
sb.WriteString(s)
}
return sb.String()
}
sync.Pool
var bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func processData(data []byte) []byte {
buf := bufferPool.Get().(*bytes.Buffer)
buf.Reset()
defer bufferPool.Put(buf)
buf.Write(data)
return buf.Bytes()
}
var sbPool = sync.Pool{
New: func() interface{} {
return &strings.Builder{}
},
}
func buildString(parts []string) string {
sb := sbPool.Get().(*strings.Builder)
sb.Reset()
defer sbPool.Put(sb)
for _, part := range parts {
sb.WriteString(part)
}
return sb.String()
}
Zero-Copy Techniques
func parseHeader(header []byte) (key, value []byte) {
i := bytes.IndexByte(header, ':')
if i < 0 {
return nil, nil
}
return header[:i], header[i+1:]
}
type Parser struct {
buf []byte
}
func (p *Parser) Parse(data []byte) error {
p.buf = p.buf[:0]
p.buf = append(p.buf, data...)
return nil
}
func writeResponse(w io.Writer, data interface{}) error {
enc := json.NewEncoder(w)
return enc.Encode(data)
}
Garbage Collection Tuning
GC Control
import "runtime/debug"
debug.SetGCPercent(100)
runtime.GC()
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Printf("Alloc = %v MB\n", stats.Alloc/1024/1024)
fmt.Printf("TotalAlloc = %v MB\n", stats.TotalAlloc/1024/1024)
fmt.Printf("Sys = %v MB\n", stats.Sys/1024/1024)
fmt.Printf("NumGC = %v\n", stats.NumGC)
GOGC Environment Variable
GOGC=100 ./myapp
GOGC=50 ./myapp
GOGC=200 ./myapp
GOGC=off ./myapp
Concurrency Optimization
Reduce Lock Contention
type BadCache struct {
mu sync.Mutex
items map[string]interface{}
}
type GoodCache struct {
mu sync.RWMutex
items map[string]interface{}
}
func (c *GoodCache) Get(key string) interface{} {
c.mu.RLock()
defer c.mu.RUnlock()
return c.items[key]
}
type ShardedCache struct {
shards [256]*shard
}
type shard struct {
mu sync.RWMutex
items map[string]interface{}
}
func (c *ShardedCache) Get(key string) interface{} {
shard := c.getShard(key)
shard.mu.RLock()
defer shard.mu.RUnlock()
return shard.items[key]
}
Channel Buffering
ch := make(chan int)
ch := make(chan int, 100)
Atomic Operations
import "sync/atomic"
type Counter struct {
value int64
}
func (c *Counter) Increment() {
atomic.AddInt64(&c.value, 1)
}
func (c *Counter) Value() int64 {
return atomic.LoadInt64(&c.value)
}
Algorithmic Optimization
Map Pre-sizing
func badMap(items []Item) map[string]Item {
m := make(map[string]Item)
for _, item := range items {
m[item.ID] = item
}
return m
}
func goodMap(items []Item) map[string]Item {
m := make(map[string]Item, len(items))
for _, item := range items {
m[item.ID] = item
}
return m
}
Avoid Unnecessary Work
func process(items []Item) {
for _, item := range items {
if isValid(item) {
result := expensiveComputation(item)
if result > threshold {
handleResult(result)
}
}
}
}
func process(items []Item) {
for _, item := range items {
if !isValid(item) {
continue
}
result := expensiveComputation(item)
if result <= threshold {
continue
}
handleResult(result)
}
}
func process(items []Item) {
for _, item := range items {
if item.IsSimple() {
handleSimple(item)
continue
}
handleComplex(item)
}
}
Runtime Tuning
GOMAXPROCS
import "runtime"
runtime.GOMAXPROCS(runtime.NumCPU())
Environment Variables
GOMAXPROCS=8 ./myapp
GOGC=100 ./myapp
GOMEMLIMIT=4GiB ./myapp
GODEBUG=gctrace=1 ./myapp
Performance Patterns
Inline Functions
func add(a, b int) int {
return a + b
}
Avoid Interface Allocations
func badPrint(value interface{}) {
fmt.Println(value)
}
func printInt(value int) {
fmt.Println(value)
}
func printString(value string) {
fmt.Println(value)
}
Batch Operations
for _, item := range items {
db.Insert(item)
}
db.BatchInsert(items)
Best Practices
- Profile before optimizing - Measure, don't guess
- Focus on hot paths - Optimize the 20% that matters
- Reduce allocations - Reuse objects, pre-allocate
- Use appropriate data structures - Map vs slice vs array
- Minimize lock contention - Use RWMutex, sharding
- Benchmark changes - Use benchstat for comparisons
- Test with race detector -
go test -race
- Monitor in production - Use profiling endpoints
- Balance readability and performance - Don't over-optimize
- Use PGO - Profile-guided optimization (Go 1.20+)
Profile-Guided Optimization (PGO)
go build -o myapp
./myapp -cpuprofile=default.pgo
go build -pgo=default.pgo -o myapp-optimized
Resources
Additional resources in:
assets/examples/ - Performance optimization examples
assets/benchmarks/ - Benchmark templates
references/ - Links to profiling guides and performance papers