Musée d'Orsay, Rue de la Légion d'Honneur, Paris, France

Image by: goffredo crollalanza

Understanding Hashed Time Wheel

Published on: September 13, 2025

A beginner-friendly explanation of the Hashed Time Wheel algorithm for managing timers efficiently.

Table of Contents

Introduction

Efficient timer management is critical in networking, scheduling, and distributed systems.
Traditional approaches often become slow when there are many timers.
The Hashed Time Wheel (HTW) algorithm solves this by providing a simple yet efficient way to manage thousands of timers.

Why Do We Need Hashed Time Wheel?

How Does It Work?

Imagine a clock:

If the timer does not fit into the first round, it waits for multiple rotations.

Example

Suppose:

If a timer is set for 10 seconds:

The diagram below shows how different timers are positioned in the wheel. Each timer is placed in a specific slot based on its delay, and longer timers have a “rounds” counter indicating how many full wheel rotations they must wait before execution. The current pointer moves clockwise with each tick.

graph TD
    subgraph "Time Wheel (8 slots, tick=1s)"
        A[Slot 0
Current] -.-> B[Slot 1] B --> C[Slot 2
Timer 4
rounds: 1] C --> D[Slot 3
Timer 1
Timer 2
rounds: 0] D --> E[Slot 4] E --> F[Slot 5] F --> G[Slot 6] G --> H[Slot 7] H -.-> A end subgraph "Example Timers" T1["Timer 1: 3s
slot = (0+3) % 8 = 3
rounds = 0"] T2["Timer 2: 3s
slot = (0+3) % 8 = 3
rounds = 0"] T3["Timer 3: 8s
slot = (0+8) % 8 = 0
rounds = 1"] T4["Timer 4: 10s
slot = (0+10) % 8 = 2
rounds = 1"] end T1 --> D T2 --> D T3 --> A T4 --> C style A fill:#e1f5fe style D fill:#fff3e0 style C fill:#fff3e0

Implementation

type TimerCallback = () => void;

class Timer {
  rounds: number;
  callback: TimerCallback;

  constructor(rounds: number, callback: TimerCallback) {
    this.rounds = rounds;
    this.callback = callback;
  }
}

class HashedTimeWheel {
  private slots: Timer[][];
  private currentSlot: number = 0;
  private intervalId?: NodeJS.Timeout;

  constructor(
    private tickDuration: number, // in ms
    private wheelSize: number
  ) {
    this.slots = Array.from({ length: wheelSize }, () => []);
  }

  addTimer(delay: number, callback: TimerCallback) {
    const ticks = Math.floor(delay / this.tickDuration);
    const slot = (this.currentSlot + ticks) % this.wheelSize;
    const rounds = Math.floor(ticks / this.wheelSize);

    if (!this.slots[slot]) {
      this.slots[slot] = [];
    }
    this.slots[slot].push(new Timer(rounds, callback));
  }

  start() {
    if (this.intervalId) return;

    this.intervalId = setInterval(() => {
      console.log("tick", this.currentSlot);
      const timers = this.slots[this.currentSlot] ?? [];

      for (let i = 0; i < timers.length; i++) {
        const timer = timers[i];
        if (timer?.rounds === 0) {
          timer?.callback();
          timers.splice(i, 1);
          i--;
        } else {
          timer!.rounds--;
        }
      }

      this.currentSlot = (this.currentSlot + 1) % this.wheelSize;
    }, this.tickDuration);
  }

  stop() {
    if (this.intervalId) clearInterval(this.intervalId);
  }
}

// Example usage
const wheel = new HashedTimeWheel(1000, 8); // tick = 1s, 8 slots
wheel.start();

wheel.addTimer(3000, () => console.log("Timer 1 fired after 3s"));
wheel.addTimer(3000, () => console.log("Timer 2 fired after 3s"));

wheel.addTimer(8000, () => console.log("Timer 3 fired after 8s"));

wheel.addTimer(10000, () => console.log("Timer 4 fired after 10s"));

wheel.addTimer(16000, () => console.log("Timer 5 fired after 16s"));

We implemented a simple Hashed Time Wheel with 8 slots and a tick duration of 1 second. Timers are added with different delays, and the wheel executes them when their time comes.

Output

bun run ./index
tick 0
tick 1
tick 2
tick 3
Timer 1 fired after 3s
Timer 2 fired after 3s
tick 4
tick 5
tick 6
tick 7
tick 0
Timer 3 fired after 8s
tick 1
tick 2
Timer 4 fired after 10s
tick 3
tick 4
tick 5
tick 6
tick 7
tick 0
Timer 5 fired after 16s
tick 1
tick 2
tick 3

Conclusion

Hashed Time Wheel is a simple but powerful algorithm. It makes timer management scalable, which is why it’s widely used in real-world systems. If you’re building anything that needs to handle thousands of timers, this algorithm is worth learning.

Tags: #timers #algorithms #en