Never asks the OSfor another byte
A deterministic-memory task queue, written in C. You give it a memory budget at startup — it uses exactly that, tells you precisely what it is using, and never grows.
Measured on one machine with bench/run.sh. Nothing here is estimated.
Every number herecame off a run you can repeat.
One machine, one build, one afternoon — reproducible with bench/run.sh. Nothing below is estimated, extrapolated, or taken from documentation.
- Apple M4 Pro (12 cores), 24 GB
- macOS 26.5.1, arm64
- Apple clang 17, quicxd built -O2
- Default 8 MB PMAD pool
- Loopback TCP, no network hop
- 8 worker processes, 8 producer connections, C clients
End to end, single thread. Closed loop, 8 connections × 32 in flight, 8 workers. 443,912 tasks in the measured window, 0 errors, 0 dropped connections. Repeat runs land between 74k and 75k.
One task is a full lifecycle — submit, ack, dispatch, parse, done, notify. Five protocol messages, not one enqueue.
- p5051 µs
- p9067 µs
- p99111 µs
- p99.9174 µs
Open loop at 40k/s offered, timed from the scheduled send — stalls are charged in full, not hidden.
- idle RSS
- 9,584 KB
- after 443,912 tasks
- 9,584 KB
- peak of 8 MB pool
- 10.7%
Not low growth — no growth. The pool is mapped once at startup and every allocation comes out of it.
| offered | p50 | p99 | p99.9 |
|---|---|---|---|
| 10k/s | 52 µs | 116 µs | 157 µs |
| 20k/s | 52 µs | 99 µs | 163 µs |
| 40k/s | 51 µs | 111 µs | 174 µs |
How it was measured
The methodology is the difference between a benchmark and a marketing claim, so it belongs here and not in a footnote.
- C clients, not Python
- A Python client tops out around 50–100k socket ops/sec and contends on the GIL across threads, so it saturates before the daemon does and ends up measuring itself.
- Latency is submit → done
- Not submit → ack. An ack only means the daemon received the frame; it never touches a worker. For a task queue, the number that matters is when the work is finished.
- Open loop for latency, closed loop for throughput
- Latency runs put tasks on a fixed schedule and charge stalls against the scheduled send time — the standard correction for coordinated omission. Closed-loop latency is not quoted, because a client that backs off when the server slows cannot measure the server slowing.
- Real payloads, really parsed
- nginx combined-format access-log lines, 120–260 bytes. Workers parse them — IP, method, path hash, status, bytes — and report per-status totals, so a run can be verified rather than trusted.
- One machine, loopback TCP
- No network hop. Real deployments will be slower.
- The harness checks itself
- 256 outstanding requests ÷ 74.3k/s = 3.4 ms, and measured closed-loop p50 was 3.6 ms. Little's Law agrees, so the instrument is measuring queueing and not itself.
Six opinions.So you don't have to make them.
What makes Quicx, Quicx — six deliberate choices, baked into every frame, every slab, every byte.
One daemon.Every piece in its place.
Producers submit tasks over a compact binary protocol. The Quicx daemon routes, queues and dispatches work to a fixed pool of workers — all backed by PMAD, our deterministic slab allocator.
What Quicx does not do.Because some of the speed is work it is skipping.
Quicx is a fast in-memory broker, not a durable one. If you need at-least-once delivery, use beanstalkd or Redis Streams — and if you need an exact memory ceiling, keep reading.
- Persistence
A restart loses everything queued.
- Redelivery
If a worker dies mid-task, the task is lost and the producer is not notified.
- Retries
No automatic retry, no dead-lettering.
- Priorities, delays, named queues
One global FIFO.
- Client libraries beyond Java
dev.quicx:quicx-client is the only one. Every other language talks the wire protocol directly — it is documented and small.
- Payloads above 1 KB
PROTOCOL_MAX_PAYLOAD is 1024 bytes, matching the largest PMAD size class. Oversized frames get a clean MSG_ERROR.
- Multiple cores
Single-threaded today. Scale out by running several daemons behind a TCP load balancer.
Only the Quicx row was measured here. Every other figure comes from vendor documentation or third-party benchmarks on unknown hardware, and is included for rough orientation — not as a head-to-head result.
| throughput | latency | provenance | |
|---|---|---|---|
| Quicx | 74.3k tasks/s (1 thread) | 51 µs p50 end-to-end | measured here |
| Redis (LPUSH) | ~161k commands/s | 0.30 ms p50, one command | reported |
| RabbitMQ | ~40k msg/s | — | reported |
| Kafka | >1M msg/s, batched | ~ms | reported |
| beanstalkd | — | — | no comparable figure found |
LPUSH is one command, and a real Redis job queue needs LPUSH + BRPOP + an ack. Normalised per completed job, Redis’s ~161k commands/sec is on the order of 50k jobs/sec.