ExamplesBasic SPSC

This page demonstrates a step-by-step SP8D SPSC (Single-Producer, Single-Consumer) example for JavaScript and Node.js. Learn how to implement ultra-low-latency, lock-free channels for high-performance messaging in your apps.

SP8D SPSC Example: Single-Producer Single-Consumer in JavaScript & Node.js

The classic “lock-free queue” pattern—one producer, one consumer, highest throughput, zero overhead. SPSC is the fastest possible channel mode: no locks, no contention, and cache-friendly.

SPSC (Single-Producer, Single-Consumer) channels are the gold standard for ultra-low-latency, lock-free communication between exactly two threads or tasks. Use this pattern when you need maximum throughput and absolute ordering, with zero contention or ambiguity.


Minimal SPSC Example (Node.js or Browser)

This example walks you through the simplest SPSC channel: one producer, one consumer, zero contention. Perfect for ultra-low-latency pipelines or thread handoff. The diagram below shows the data flow.

Diagram: Producer uses send() to move data to the channel. Consumer uses recv() to receive it. This direct handoff is what enables SPSC’s ultra-low latency and simplicity.

minimal-spsc.ts
import { createChannel } from "@sp8d/core";
 
// Create an SPSC channel with 4 slots, each slot holding up to 16 bytes.
const { channel } = createChannel({ slots: 4, slotSize: 16, mode: "SPSC" });
 
// Producer sends messages
for (let i = 0; i < 8; ++i) {
  // Wait if channel is full (backpressure)
  while (!channel.send(new Uint8Array([i, i * 10]))) {
    // Buffer is full, so producer waits and retries (busy-wait)
  }
  console.log("Sent:", i);
}
 
// Consumer receives messages
let received: Uint8Array | null;
while ((received = channel.recv()) !== null) {
  console.log("Received:", received);
}
⚠️

The busy-wait loop (while (!send)) is for demonstration only. In production, use sendAsync() or a backpressure-aware event loop to avoid wasting CPU cycles.

Async/Real-World Example

For real-world, non-blocking usage, use sendAsync() and the async iterator as shown below.

async-spsc.ts
// Producer (async)
for (let i = 0; i < 8; ++i) {
  await channel.sendAsync(new Uint8Array([i, i * 10]));
  console.log("Sent:", i);
}
 
// Consumer (async)
for await (const received of channel) {
  console.log("Received:", received);
}

What’s happening?

  • Producer: Calls send() in a loop—respects backpressure if the buffer is full.
  • Consumer: Calls recv() repeatedly—gets every value, in order, with no races or drops.
  • SPSC Mode Guarantee: Guarantees simple “ping-pong” correctness: no overwrites, slot loss, or ambiguity.

Backpressure is critical for lossless, high-throughput systems. Notice the producer waits (while (!send)) if the ring is full. This ensures you never lose data—even under burst conditions.

The output below shows the expected send/receive order for this example. If you run producer and consumer in separate threads, the interleaving may differ, but all messages will be delivered in order.

Sent: 0
Sent: 1
Sent: 2
Sent: 3
Received: Uint8Array([0, 0])
Received: Uint8Array([1, 10])
Received: Uint8Array([2, 20])
Received: Uint8Array([3, 30])
Sent: 4
Sent: 5
Sent: 6
Sent: 7
Received: Uint8Array([4, 40])
Received: Uint8Array([5, 50])
Received: Uint8Array([6, 60])
Received: Uint8Array([7, 70])
⚠️
  • send() returns false when full; always check for backpressure.

  • recv() returns null when channel is empty.

  • For browser use, producer and consumer may be in separate threads—see browser recipes.

  • For async use, see recvAsync() or the async iterator.

  • If you see dropped messages, check your slot count and backpressure handling.

  • For debugging, use diagnostics or enable verbose logging.

SPSC is the fastest mode, but only if you stick to the single-producer/single-consumer contract. If you break this contract, you may see data loss or protocol errors—use MPSC/MPMC for more complex patterns.

How does this work under the hood?

For a complete explanation of the slot state machine—including slot lifecycle, state transitions, atomic operations, and recovery—see the Slot State Machine documentation.

Where to Go Next