Go Performance
Expert guidance for writing efficient, high-performance Go code.
Quick Reference
| Concern | Solution | Impact | |---------|----------|--------| | String concatenation in loops | strings.Builder | O(n) vs O(n²) | | Repeated allocations | sync.Pool | Reduces GC pressure | | Large byte slice to string conversion | unsafe package (carefully) | Avoids allocation | | I/O operations | bufio.Scanner/buffered writers | Reduces syscalls | | Defer in tight loops | Move defer outside function | Prevents memory buildup | | Premature optimization | Don't do it | Measure first |
What Do You Need?
- String operations - Building, concatenating, converting
- Memory allocations - Reducing allocations, object reuse
- I/O efficiency - Buffered operations, batch processing
- Resource pooling - sync.Pool for frequently allocated objects
- Benchmarking - How to measure improvements
Specify a number or describe your performance concern.
Routing
| Response | Reference to Read | |----------|-------------------| | 1, "string", "concat", "build" | strings.md | | 2, "allocation", "memory", "pool" | allocations.md | | 3, "io", "file", "reader", "writer" | io.md | | 4, "benchmark", "measure", "profile" | benchmarking.md | | 5, general performance | Read relevant references |
Critical Rules
- Measure before optimizing: Use benchmarks to identify real bottlenecks
- strings.Builder for concatenation: Never use + in loops
- Avoid defer in tight loops: Defers accumulate until function return
- Use bufio for I/O: Reduces system call overhead
- sync.Pool for reuse: Pool frequently allocated objects
- Prefer fmt.Errorf over errors.New: For error wrapping context
Performance Impact Table
| Issue | Performance Cost | Fix | |-------|------------------|-----| | String + in loop | O(n²) allocations | strings.Builder | | Defer in loop | Unbounded memory | Move to separate function | | Byte to string conversion | Allocates new string | unsafe.String (careful) | | Unbuffered I/O | System call per byte | bufio.Reader/Writer | | Repeated allocations | High GC pressure | sync.Pool | | Substring allocations | O(n) per operation | Use []byte views |
Common Optimizations
Strings
// Bad: O(n²) allocations
func build(items []string) string {
var s string
for _, item := range items {
s += item + "," // New string each iteration
}
return s
}
// Good: O(n) with pre-allocation
func build(items []string) string {
var b strings.Builder
b.Grow(len(items) * 10) // Pre-allocate if you can estimate
for _, item := range items {
b.WriteString(item)
b.WriteByte(',')
}
return b.String()
}
Defer in Loops
// Bad: Defers accumulate until function returns
func process(files []string) error {
for _, f := range files {
file, err := os.Open(f)
if err != nil {
return err
}
defer file.Close() // BAD: All deferred until return!
}
return nil
}
// Good: Each defer released when function returns
func process(files []string) error {
for _, f := range files {
if err := processFile(f); err != nil {
return err
}
}
return nil
}
func processFile(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close() // GOOD: Released when processFile returns
// ...
return nil
}
sync.Pool
var bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func getBuffer() *bytes.Buffer {
return bufferPool.Get().(*bytes.Buffer)
}
func putBuffer(b *bytes.Buffer) {
b.Reset()
bufferPool.Put(b)
}
Reference Index
| File | Topics | |------|--------| | strings.md | Builder, Reader, efficient concatenation | | allocations.md | sync.Pool, escape analysis, reduction strategies | | io.md | bufio, Scanner, buffered writers, chunking | | benchmarking.md | Writing benchmarks, pprof, flame graphs |
Success Criteria
Code is performant when:
- benchmarks show improvement (measure, don't guess)
- strings.Builder used for string building in loops
- no defer in tight loops
- sync.Pool used for frequently allocated objects
- bufio used for I/O operations
- allocations are minimized (check with -benchmem)