package main

import (
	"fmt"
	"runtime"
	"slices"
	"sync"
)

// hitungTugas mensimulasikan kerja CPU-bound murni dengan hasil tetap,
// sehingga output program tetap deterministik meski dieksekusi paralel.
func hitungTugas(n int) int {
	total := 0
	for i := 1; i <= 10_000; i++ {
		total += i * (n + 1)
	}
	return total
}

func main() {
	jumlahTugas := 8

	// Pembanding: eksekusi berurutan, satu tugas selesai baru tugas berikutnya.
	urutan := make([]int, jumlahTugas)
	for i := range jumlahTugas {
		urutan[i] = hitungTugas(i)
	}

	// Worker pool: sejumlah runtime.NumCPU() goroutine mengambil tugas
	// dari channel yang sama, hasil ditulis ke indeks masing-masing.
	hasil := make([]int, jumlahTugas)
	tugas := make(chan int)
	var wg sync.WaitGroup

	jumlahWorker := runtime.NumCPU()
	for w := 0; w < jumlahWorker; w++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for n := range tugas {
				hasil[n] = hitungTugas(n) // tiap indeks hanya ditulis satu worker
			}
		}()
	}

	// Penyalur tugas: kirim semua indeks lalu tutup channel agar worker
	// keluar dari loop range.
	for i := range jumlahTugas {
		tugas <- i
	}
	close(tugas)
	wg.Wait()

	fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))
	fmt.Println("Worker dibuat:", jumlahWorker, "(setara runtime.NumCPU)")
	fmt.Println("Hasil paralel identik dengan berurutan:", slices.Equal(hasil, urutan))
	fmt.Println("Hasil terurut berdasar nomor tugas:", hasil)
}
