Thread pool in Go
Go has no OS thread pool in the standard library. You
rarely need one: goroutines are cheap and the Go runtime already
multiplexes them onto a small set of kernel threads (GOMAXPROCS).
To get the same functionality as a thread pool — limit
concurrency and reuse workers — use a worker pool of
goroutines reading jobs from a channel. See
What is Thread Pool? and
Goroutines.
1. Worker pool — N goroutines + jobs channel
Start a fixed number of worker goroutines. Producers send jobs on a channel; workers process and loop for the next job.
package main
import "fmt"
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("worker %d processing job %d\n", id, job)
results <- job * 2
}
}
func main() {
const numWorkers = 4
jobs := make(chan int, 10)
results := make(chan int, 10)
// start fixed pool of workers
for w := 0; w < numWorkers; w++ {
go worker(w, jobs, results)
}
// submit 10 jobs
for j := 1; j <= 10; j++ {
jobs <- j
}
close(jobs)
// collect results
for r := 0; r < 10; r++ {
fmt.Println("result:", <-results)
}
}
2. Worker pool with sync.WaitGroup
Same idea, but main waits for all workers to finish before
exiting.
package main
import (
"fmt"
"sync"
)
func main() {
const numWorkers = 4
jobs := make(chan int, 20)
var wg sync.WaitGroup
for w := 0; w < numWorkers; w++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for job := range jobs {
fmt.Println("worker", id, "job", job)
}
}(w)
}
for j := 1; j <= 10; j++ {
jobs <- j
}
close(jobs)
wg.Wait()
fmt.Println("all workers done")
}
3. Third-party goroutine pool — ants
When you want a reusable goroutine pool with a task API (closest to
Java's ExecutorService), use a library such as
github.com/panjf2000/ants/v2.
package main
import (
"fmt"
"sync"
"github.com/panjf2000/ants/v2"
)
func main() {
pool, _ := ants.NewPool(4) // max 4 concurrent goroutines
defer pool.Release()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
n := i
_ = pool.Submit(func() {
defer wg.Done()
fmt.Println("task", n)
})
}
wg.Wait()
}
Summary: Go achieves thread-pool behavior with a bounded set of worker goroutines + channel queue. The runtime handles OS thread scheduling; you control application-level concurrency.