Concurrency and Packages
Goroutine Result Slots
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
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)
}
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.WaitGroupwg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}
pass 1 of 213for 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}wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0}
pass 2 of 213for 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}wg.Wait()
22wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr B⟩}, sema:0x0}.Wait()func(slot int)
pass 1 of 214wg.Add(1)15go func(slot1 int) {16 defer wg.Done()wg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr C⟩}, sema:0x0}
pass 2 of 214wg.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)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 {total ← 10
pass 1 of 224total := 025for _, value10 := range results[]int{10, 20} {26 total→ 10 += value1027}total ← 30
pass 2 of 224total := 025for _, value20 := range results[]int{10, 20} {26 total→ 30 += value2027}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
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.WaitGroupwg ← 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}wg.Wait()
22wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}.Wait()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)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 {total ← 10
24total := 025for _, value10 := range results[]int{10} {26 total→ 10 += value1027}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
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.WaitGroupwg ← sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr A⟩}, sema:0x0}
pass 1 of 313for 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 pass indexwg1 0 sync.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} 2 1 sync.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} 3 2 sync.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} wg.Wait()
22wgsync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr C⟩}, sema:0x0}.Wait()base ← 3, results[slot] ← 30
pass 1 of 314wg.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 pass slotwgbaseresults[slot]1 2 sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr D⟩}, sema:0x0} 3 0 → 30 2 1 sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr E⟩}, sema:0x0} — — 3 0 sync.WaitGroup{noCopy:sync.noCopy{}, state:atomic.Uint64{_:atomic.noCopy{}, _:atomic.align64{}, v:⟨addr E⟩}, sema:0x0} 2 0 → 20 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 {total ← 10
pass 1 of 324total := 025for _, value10 := range results[]int{10, 20, 30} {26 total→ 10 += value1027}All 3 passes — pass 1 is the card above pass valuetotal1 10 0 → 10 2 20 10 → 30 3 30 30 → 60 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