ants
A high-performance goroutine pool for Go that recycles and limits concurrent goroutines to cut memory overhead.
Repository Health
Technical Analysis
ants implements a fixed- or dynamically-tunable goroutine pool for Go, letting applications cap the number of concurrently running goroutines instead of spawning one per task. It reuses worker goroutines across tasks via a swappable worker queue (a LIFO stack or a preallocated ring buffer), a background scavenger purges idle workers past their expiry, and panics inside tasks are recovered so one bad task can’t crash the pool.
Beyond the core Pool (function-per-task submission) and PoolWithFunc/PoolWithFuncGeneric (a shared function invoked per submitted argument), ants ships a MultiPool that shards work across several pools with round-robin or least-tasks load balancing to reduce lock contention at very high throughput. It’s used in production by companies like Tencent, ByteDance, and Shopify, and by open-source projects such as gnet and Milvus.
What You Get
- Fixed or unlimited-capacity pools via
NewPool, tunable at runtime withTune PoolWithFunc/PoolWithFuncGenericfor submitting arguments to one shared task functionMultiPoolfor sharding across multiple pools with round-robin or least-tasks load balancing- Automatic panic recovery per worker with a pluggable
PanicHandler - A background scavenger that purges idle workers past a configurable
ExpiryDuration - Optional pre-allocated, ring-buffer-backed worker queue (
WithPreAlloc) for latency-sensitive workloads
Common Use Cases
- Capping goroutine counts in high-throughput HTTP/RPC servers handling bursts of concurrent requests
- Batch-processing pipelines that fan out large numbers of short-lived tasks without exhausting memory
- Building blocks for higher-level frameworks (e.g. gnet) that need a managed worker pool under the hood
- Any place unlimited goroutine-per-task spawning would risk OOM or scheduler thrash under load spikes
Under The Hood
Architecture
A poolCommon type in ants.go holds the shared capacity/state/worker-queue logic; Pool (pool.go) embeds poolCommon and adds Submit, while PoolWithFunc/PoolWithFuncGeneric add an invocation-with-argument variant of the same core. MultiPool (multipool.go) composes multiple Pool instances behind a LoadBalancingStrategy (RoundRobin/LeastTasks), selecting a target pool through an atomic index or a scan for least pending tasks. The worker abstraction (the worker and workerQueue interfaces in worker_queue.go) is pluggable between a LIFO workerStack (worker_stack.go, using binary search over sorted last-used timestamps to batch-expire idle workers) and a preallocated workerLoopQueue, selected via WithPreAlloc. The retrieveWorker/revertWorker pair in ants.go forms the core scheduling primitive, guarded by a custom spinlock (pkg/sync) and a sync.Cond for blocking submitters, alongside a background purgeStaleWorkers scavenger and a low-overhead ticktock clock goroutine per pool.
Tech Stack
Pure standard-library Go (sync, sync/atomic, context, time, runtime), with a single external dependency, golang.org/x/sync/errgroup, used only to fan out MultiPool.ReleaseContext across sub-pools, plus stretchr/testify for test assertions. The module targets Go 1.19 and ships its own hand-rolled backoff spinlock (pkg/sync/spinlock.go), benchmarked in-repo against sync.Mutex. Build and CI are plain go build/go test driven by GitHub Actions (test.yml, codeql.yml) with no external build system; the deployment target is any Go binary that imports it as a library.
Code Quality
An extensive white-box test suite (ants_test.go, plus worker_stack_test.go, worker_loop_queue_test.go, and spinlock_test.go) uses testify assertions to cover pool creation, submit/tune/release/reboot edge cases, and concurrent stress, backed by example_test.go godoc-verified usage examples and a dedicated benchmark file. Errors are explicit sentinel Err* values rather than ad hoc panics, panics raised inside user tasks are recovered and routed through a pluggable PanicHandler, naming is consistent, and every exported symbol carries a doc comment. CI runs the test suite plus CodeQL static analysis on every pull request.
What Makes It Unique
The pool treats its worker queue as a swappable strategy — a LIFO stack with binary-search-based batch expiry versus a preallocated ring buffer — trading memory eagerness for an allocation-free steady state, and protects the hot retrieve/revert path with a hand-tuned backoff spinlock measured well ahead of sync.Mutex in the repo’s own benchmarks, rather than the channel-based dispatch most comparable worker-pool libraries use. MultiPool’s least-tasks/round-robin sharding for reducing lock contention at scale is a further refinement uncommon among comparable Go worker-pool libraries.
Used by 2 apps in this directory
BillionMail
Marketing
Self-hosted email server and marketing platform that gives you unlimited sending, full deliverability control, and AI-assisted campaigns without monthly fees.
TDengine
Databases
A high-performance, open-source time-series database built in C for IoT, connected vehicles, and industrial monitoring workloads, with built-in stream processing, caching, and data subscription.