// A worker pool in Go: structs with methods, goroutines, channels,
// and a WaitGroup.
package main

import (
	"fmt"
	"sync"
)

type Job struct {
	ID   int
	Data int
}

type Result struct {
	JobID  int
	Output int
}

func worker(jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
	defer wg.Done()
	for job := range jobs {
		results <- Result{JobID: job.ID, Output: job.Data * job.Data}
	}
}

func main() {
	const workers = 3
	jobs := make(chan Job, 8)
	results := make(chan Result, 8)

	var wg sync.WaitGroup
	for i := 0; i < workers; i++ {
		wg.Add(1)
		go worker(jobs, results, &wg)
	}

	for i := 1; i <= 8; i++ {
		jobs <- Job{ID: i, Data: i}
	}
	close(jobs)

	go func() {
		wg.Wait()
		close(results)
	}()

	total := 0
	for r := range results {
		total += r.Output
	}
	fmt.Printf("sum of squares = %d\n", total)
}
