Skip to content

Performance: MessageQueue.qsize() is O(n) linear scan #103

Description

@TexasCoding

From Wave 5 performance audit, finding F-R-01. Severity: medium. Measured.

Code

`kalshi/ws/backpressure.py:80-82`:
```python
def qsize(self) -> int:
return sum(1 for item in self._buffer if item is not _SENTINEL)
```

Measurement

  • `qsize()` with 1000 items: 22.474 µs/call
  • `len(buffer)`: 0.035 µs/call

Three orders of magnitude — 600× regression on every call.

Why this matters

Anyone polling `qsize()` from a monitoring loop, a hot consumer, or a backpressure-aware throttle pays 22 µs per call at `maxsize=1000`. The linear scan exists only to subtract the sentinel; at most one sentinel ever sits in the deque, and only at shutdown.

Fix

Either:

  • (a) Track a counter (increment in `put`, decrement in `get`). O(1).
  • (b) Return `len(self._buffer) - (1 if self._closed and self._buffer and self._buffer[-1] is _SENTINEL else 0)`. O(1).

(b) is the smaller change.

Related (low priority)

F-R-02 / F-P-15: the `_buffer` is also `collections.deque(maxlen=None)`. The bound is enforced manually in `put()`, but `maxlen=None` defeats the deque's own ring-buffer safety. Worth setting `maxlen=maxsize + 1` (reserve one slot for sentinel) as defense-in-depth.

Metadata

Metadata

Assignees

No one assigned

    Labels

    polishCode-quality and DX improvements; non-functionalwsWebSocket-related

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions