Process a []int through a CPU-bound worker pool
You have a CPU-bound function heavyCompute(n int) int that processes one int. Implement processAll(nums []int) []int that runs the whole slice through it in parallel using a worker pool. The output must preserve order — out[i] corresponds to nums[i]. Requirements: size the pool to the number of CPU cores (runtime.NumCPU()), not one goroutine per element; distribute work over a channel; synchronize with sync.WaitGroup.
func processAll(nums []int) []int {
// your code here
}
Write the implementation.
For CPU-bound work, size the pool to runtime.NumCPU() — extra goroutines beyond the cores only add scheduling cost. Send indices over a jobs channel; each worker writes out[i] = heavyCompute(nums[i]) to its own index, so no lock is needed and order is preserved. A sync.WaitGroup blocks until every worker finishes.
- ✗Spawning one goroutine per element for CPU-bound work, so thousands of goroutines thrash the scheduler instead of saturating the cores
- ✗Collecting results by
appendinto a shared slice under a mutex, which serializes the workers and scrambles output order - ✗Sizing the pool to the element count or a hard-coded constant instead of
runtime.NumCPU()
- →Why does adding more workers than CPU cores fail to speed up CPU-bound work?
- →How would the concurrency helper
errgroupwithSetLimitreplace this manual pool?
Skeleton to implement
There is no point splitting CPU-bound work finer than the core count: more goroutines than cores do not speed up the computation, they only load the scheduler. Handing out indices over a jobs channel balances the load dynamically when per-element cost is uneven. Each worker writes to its own index out[i] — so no lock and no shared append are needed, and order is preserved for free.
func processAll(nums []int) []int {
out := make([]int, len(nums))
jobs := make(chan int, len(nums)) // element indices
var wg sync.WaitGroup
workers := runtime.NumCPU() // size to cores, not to elements
for w := 0; w < workers; w++ {
wg.Add(1)
go func() {
defer wg.Done()
for i := range jobs { // take the next free index
out[i] = heavyCompute(nums[i]) // write own index — no locking
}
}()
}
for i := range nums {
jobs <- i
}
close(jobs) // workers leave the range loop once drained
wg.Wait() // wait for every worker
return out
}