liveBook · Manning

Performance

As explained in 100 Go Mistakes and How to Avoid Them

Performance is a measure of how efficiently a program performs its work, commonly including execution time and resource consumption.

A faster-looking implementation is not necessarily faster. Performance depends on the work a program does, including allocations, copying, and contention. Make code correct and clear first; optimize paths where speed or efficiency matters, and measure alternatives rather than guessing. section 8.2 section 12.0

Three common Go choices show why context matters:

  • Growing an empty slice with append repeatedly allocates larger backing arrays and copies elements. If the result size is known, set the capacity before appending or set the length and assign by index. If only an upper bound is known, capacity preserves append's flexibility. section 3.5
  • Repeated string += creates a new string on each iteration. strings.Builder writes to an internal buffer; Grow reserves space when the final length is known. Do not use one builder concurrently. section 5.4
  • reflect.DeepEqual can compare values containing slices, but runtime reflection costs more than ==. For performance-sensitive runtime comparisons, consider field-by-field equality; first check for an existing standard-library comparison function. section 3.13

Measure the slice conversion

With one million input elements, benchmarks reported 49,739,882 ns/op for an initially empty slice, 13,438,544 ns/op with capacity reserved, and 12,800,411 ns/op with length set. The direct-index version was slightly faster, but both sized versions avoided repeated backing-array growth. section 3.5

func concat(values []string) string {
    total := 0
    for i := 0; i < len(values); i++ {     #1
        total += len(values[i])
    }
 
    sb := strings.Builder{}
    sb.Grow(total)                         #2
    for _, value := range values {
        _, _ = sb.WriteString(value)
    }
    return sb.String()
}

This concatenation implementation totals the input lengths before calling Grow, making the reservation explicit. section 5.4

Do not add concurrency merely to make a program faster. Its benefit depends on what can run in parallel and how much contention the work creates. section 8.2

How 100 Go Mistakes and How to Avoid Them covers it

How deep it goes
Traces slice reallocations and string copying, then benchmarks alternatives; stops short of a general profiling procedure.
Examples
Compares one-million-element slice conversions and three string-concatenation implementations using ns/op benchmarks.
What it assumes
Assumes familiarity with Go structs, slices, loops, and benchmark output; does not teach basic syntax.
What you can do after
Diagnose/debug with it by benchmarking alternatives, preallocating slices, and reserving strings.Builder capacity when sizes are known.
How it connects
Connects performance to slice capacity, garbage collection, string immutability, and strings.Builder.

Also explained in

Compare how 40 books explain performance →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Go Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.