Token bucket rate limiter for threads

Python
import threading
import time


class TokenBucket:
    """Allow bursts up to `capacity` while enforcing an average `rate`."""

    def __init__(self, rate: float, capacity: int) -> None:
        self.rate = rate
        self.capacity = capacity
        self.tokens = float(capacity)
        self.updated = time.monotonic()
        self.lock = threading.Lock()

    def acquire(self, amount: int = 1) -> float:
        """Block until `amount` tokens exist; return the seconds spent waiting."""
        if amount > self.capacity:
            raise ValueError("amount exceeds bucket capacity")
        waited = 0.0
        while True:
            with self.lock:
                now = time.monotonic()
                self.tokens = min(self.capacity, self.tokens + (now - self.updated) * self.rate)
                self.updated = now
                if self.tokens >= amount:
                    self.tokens -= amount
                    return waited
                missing = (amount - self.tokens) / self.rate
            time.sleep(missing)
            waited += missing


if __name__ == "__main__":
    bucket = TokenBucket(rate=2, capacity=5)
    print([round(bucket.acquire(), 2) for _ in range(6)])