Workers can run concurrently while writing results into stable slots that the main goroutine reads after all workers finish.

result slots Use a `WaitGroup` and one array slot per worker so final output is deterministic even when goroutines run in different orders.

Goroutine Result Slots

workerCount
goroutine_result_slots.go
Replay: real traced execution (multi-file project)
package main

import (
	"fmt"
	"sync"
)

func main() {
	var workerCount = 2
	results := make([]int, workerCount)
	var wg sync.WaitGroup

	for index := 0; index < workerCount; index++ {
		wg.Add(1)
		go func(slot int) {
			defer wg.Done()
			base := slot + 1
			results[slot] = base * 10
		}(index)
	}

	wg.Wait()

	total := 0
	for _, value := range results {
		total += value
	}

	fmt.Println("workers=", workerCount)
	fmt.Println("results=", results)
	fmt.Println("total=", total)
}
package main

import (
	"fmt"
	"sync"
)

func main() {
	var workerCount = 1
	results := make([]int, workerCount)
	var wg sync.WaitGroup

	for index := 0; index < workerCount; index++ {
		wg.Add(1)
		go func(slot int) {
			defer wg.Done()
			base := slot + 1
			results[slot] = base * 10
		}(index)
	}

	wg.Wait()

	total := 0
	for _, value := range results {
		total += value
	}

	fmt.Println("workers=", workerCount)
	fmt.Println("results=", results)
	fmt.Println("total=", total)
}
package main

import (
	"fmt"
	"sync"
)

func main() {
	var workerCount = 3
	results := make([]int, workerCount)
	var wg sync.WaitGroup

	for index := 0; index < workerCount; index++ {
		wg.Add(1)
		go func(slot int) {
			defer wg.Done()
			base := slot + 1
			results[slot] = base * 10
		}(index)
	}

	wg.Wait()

	total := 0
	for _, value := range results {
		total += value
	}

	fmt.Println("workers=", workerCount)
	fmt.Println("results=", results)
	fmt.Println("total=", total)
}
  1. workerCount ← 2, results ← []int{0, 0}, wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}

    8func main() {9  var workerCount→ 2 = 2 //@workerCount=1, 310  results→ []int{0, 0} := make([]int, workerCount2)11  var wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0} sync.WaitGroup
  2. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}

    pass 1 of 2
    13for index0 := 0; index < workerCount2; index++ {14  wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}.Add(1)15  go func(slot int) {16    defer wg.Done()17    base := slot + 118    results[slot] = base * 1019  }(index0)20}
  3. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0}

    pass 2 of 2
    13for index1 := 0; index < workerCount2; index++ {14  wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0}.Add(1)15  go func(slot int) {16    defer wg.Done()17    base := slot + 118    results[slot] = base * 1019  }(index1)20}
  4. wg.Wait()

    22wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0}.Wait()
  5. func(slot int)

    pass 1 of 2
    14wg.Add(1)15go func(slot1 int) {16  defer wg.Done()
  6. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr C⟩}, sema:0x0}

    pass 2 of 2
    14wg.Add(1)15go func(slot0 int) {16  defer wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr C⟩}, sema:0x0}.Done()17  base→ 2 := slot1 + 118  results[slot]→ 20 = base2 * 1019}(index)
  7. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}

    22wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}.Wait()2324total→ 0 := 025for _, value := range results {
  8. total ← 10

    pass 1 of 2
    24total := 025for _, value10 := range results[]int{10, 20} {26  total→ 10 += value1027}
  9. total ← 30

    pass 2 of 2
    24total := 025for _, value20 := range results[]int{10, 20} {26  total→ 30 += value2027}
  10. fmt.Println("workers=", workerCount)

    29  fmt.Println("workers=", workerCount2)30  fmt.Println("results=", results[]int{10, 20})31  fmt.Println("total=", total30)32}
    outputworkers= 2
    results= [10 20]
    total= 30
  1. workerCount ← 1, results ← []int{0}, wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}

    8func main() {9  var workerCount→ 1 = 110  results→ []int{0} := make([]int, workerCount1)11  var wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0} sync.WaitGroup
  2. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}

    13for index0 := 0; index < workerCount1; index++ {14  wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}.Add(1)15  go func(slot int) {16    defer wg.Done()17    base := slot + 118    results[slot] = base * 1019  }(index0)20}
  3. wg.Wait()

    22wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}.Wait()
  4. base ← 1, results[slot] ← 10

    14wg.Add(1)15go func(slot0 int) {16  defer wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0}.Done()17  base→ 1 := slot0 + 118  results[slot]→ 10 = base1 * 1019}(index)
  5. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}

    22wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}.Wait()2324total→ 0 := 025for _, value := range results {
  6. total ← 10

    24total := 025for _, value10 := range results[]int{10} {26  total→ 10 += value1027}
  7. fmt.Println("workers=", workerCount)

    29  fmt.Println("workers=", workerCount1)30  fmt.Println("results=", results[]int{10})31  fmt.Println("total=", total10)32}
    outputworkers= 1
    results= [10]
    total= 10
  1. workerCount ← 3, results ← []int{0, 0, 0}, wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}

    8func main() {9  var workerCount→ 3 = 310  results→ []int{0, 0, 0} := make([]int, workerCount3)11  var wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0} sync.WaitGroup
  2. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}

    pass 1 of 3
    13for index0 := 0; index < workerCount3; index++ {14  wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}.Add(1)15  go func(slot int) {16    defer wg.Done()17    base := slot + 118    results[slot] = base * 1019  }(index0)20}
    All 3 passes — pass 1 is the card above
    passindexwg
    10sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0} sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}
    21sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0} sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0}
    32sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0} sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr C⟩}, sema:0x0}
  3. wg.Wait()

    22wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr C⟩}, sema:0x0}.Wait()
  4. base ← 3, results[slot] ← 30

    pass 1 of 3
    14wg.Add(1)15go func(slot2 int) {16  defer wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr D⟩}, sema:0x0}.Done()17  base→ 3 := slot2 + 118  results[slot]→ 30 = base3 * 1019}(index)
    All 3 passes — pass 1 is the card above
    passslotwgbaseresults[slot]
    12sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr D⟩}, sema:0x0}30 30
    21sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr E⟩}, sema:0x0}
    30sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr E⟩}, sema:0x0}20 20
  5. wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}

    22wg→ sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:0x0}, sema:0x0}.Wait()2324total→ 0 := 025for _, value := range results {
  6. total ← 10

    pass 1 of 3
    24total := 025for _, value10 := range results[]int{10, 20, 30} {26  total→ 10 += value1027}
    All 3 passes — pass 1 is the card above
    passvaluetotal
    1100 10
    22010 30
    33030 60
  7. fmt.Println("workers=", workerCount)

    29  fmt.Println("workers=", workerCount3)30  fmt.Println("results=", results[]int{10, 20, 30})31  fmt.Println("total=", total60)32}
    outputworkers= 3
    results= [10 20 30]
    total= 60