ants

A high-performance goroutine pool for Go that recycles and limits concurrent goroutines to cut memory overhead.

Library
Go
vv2.12.1
14,501stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
56/100Fair
Development Activity28
Maintenance24
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
83/100Excellent
Architecture85
Code Quality90
Innovation75
Learning Curve80

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 with Tune
  • PoolWithFunc / PoolWithFuncGeneric for submitting arguments to one shared task function
  • MultiPool for 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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search