nexus-pool
High-performance object pools for latency-sensitive applications.
Features
- Sub-100 cycle operations: ~26 cycles for local pools, ~42-68 cycles for sync pools
- Zero allocation on hot path: Pre-allocate objects at startup
- RAII guards: Objects automatically return to pool on drop
- Graceful shutdown: Guards safely drop values if pool is gone
Quick Start
use BoundedPool;
// Create a pool of 100 pre-allocated buffers
let pool = new;
// Acquire and use
let mut buf = pool.try_acquire.expect;
buf.extend_from_slice;
// Automatically returns to pool when `buf` drops
Pool Types
local::BoundedPool / local::Pool
Single-threaded pools with zero synchronization overhead.
use Pool;
// Growable pool - creates objects on demand
let pool = new;
// Always succeeds (creates new if empty)
let buf = pool.acquire;
sync::Pool
Thread-safe pool: one thread acquires, any thread can return.
use Pool;
let pool = new;
let buf = pool.try_acquire.unwrap;
// Send to another thread - returns to pool when dropped
spawn;
Design Philosophy
Predictability over generality.
This crate intentionally does not provide MPMC (multi-producer multi-consumer) pools. Here's why:
-
MPMC requires solving ABA: Generation counters, hazard pointers, or epoch-based reclamation add overhead and complexity.
-
MPMC is a design smell: If multiple threads contend for the same pool, you've created a bottleneck. The pool that was supposed to reduce latency now adds it.
-
Better alternatives exist:
- Per-thread pools (
local::Poolper thread) - Sharded pools (hash thread ID to pool index)
- Message passing (send buffers through channels)
- Per-thread pools (
If you truly need MPMC, use crossbeam::ArrayQueue.
Performance
Measured on Intel Core i9 @ 3.1 GHz:
| Pool | Acquire p50 | Release p50 | Release p99 |
|---|---|---|---|
local::BoundedPool |
26 cycles | 26 cycles | 58 cycles |
local::Pool (reuse) |
26 cycles | 26 cycles | 58 cycles |
local::Pool (factory) |
32 cycles | 26 cycles | 58 cycles |
sync::Pool (same thread) |
42 cycles | 68 cycles | 74 cycles |
sync::Pool (cross-thread) |
42 cycles | 68 cycles | 86 cycles |
Run the benchmarks yourself:
Use Cases
Trading Systems
use Pool;
// Order entry thread owns the pool
let pool = new;
// Hot path: acquire order, fill, send to matching engine
let mut order = pool.try_acquire.expect;
order.symbol = symbol;
order.price = price;
order.quantity = qty;
// Send to matching engine thread
matching_engine_tx.send.unwrap;
// Order returns to pool when matching engine drops it
Network Buffers
use BoundedPool;
// Per-connection buffer pool
let buffers = new;
loop
Minimum Supported Rust Version
Rust 1.85 or later.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.