Skip to content

Make Cache.get as fast on a hit as in 5.6.3 again - #35

Merged
avgvi merged 2 commits into
masterfrom
fix/get-store-time-fast-path
Nov 2, 2026
Merged

avgvi merged 2 commits into
masterfrom
fix/get-store-time-fast-path

Conversation

@avgvi

@avgvi avgvi commented Nov 2, 2026

Copy link
Copy Markdown
Member

Cache.get has been about 5% slower on a hit than in 5.6.3 since 5.7.0. The cause is the store_time flag added in PR #16. Every get paid for it, even when store_time wasn't asked for:

  • The query selected a 7th column, store_time. Each extra column costs about 75 ns per hit (1655 ns for the 6-column query vs 1730 ns with store_time), roughly 3%.
  • _meta_result() ran twice per call, once to wrap the default and once to wrap the result, at about 25–30 ns each, roughly 2.5%.

FanoutCache.get and DjangoCache.get go through Cache.get, so they had the same slowdown.

Change (Cache.get in core.py):

  • store_time is selected only when store_time=True. Otherwise the query is the 6-column one from 5.6.3.
  • _meta_result() runs only when expire_time, tag or store_time is asked for. A plain get returns the value directly.
  • Results are unchanged for every combination of flags, on hits, misses and timeouts.
  • get gets a scoped too-many-branches,too-many-statements disable. Splitting it into helpers would add a function call to every hit, which is the kind of cost this removes.
  • A CHANGELOG.md entry under Unreleased.

Measured with interleaved runs: each build in its own venv on the Python 3.14.6 GIL build, SQLite 3.53.1, Apple M5 Pro, 20 rounds in random order. The ratio is per round against PyPI diskcache 5.6.3, and a second 5.6.3 venv gives the noise floor.

build Cache.get hit DjangoCache.get hit
5.6.3, second venv (noise) +0.1% +0.3%
master before this change +4.8% +4.0%
this branch −0.4% −0.7%

A bisect of every commit from 5.6.3 to master put the whole step at the store_time commit (−1.4% before it, +4.6% after). Nothing between 5.7.0 and master changed get speed.

Not in this PR: Django set is still about 2% slower than 5.6.3. That comes from the fork gate from PR #13, which every write transaction passes through (about 430 ns). Cache.set without an expire stays 12–14% faster than 5.6.3, thanks to the partial indexes.

Checked:

  • The full test suite passes on Python 3.14 on macOS (804 passed, 3 skipped, 99.14% coverage). The existing store_time, expire_time and tag tests cover both query shapes on the fast and transaction paths.
  • bluecheck, flake8, isortcheck and pylint pass.

@avgvi
avgvi merged commit 569ba28 into master Nov 2, 2026
23 checks passed
@avgvi
avgvi deleted the fix/get-store-time-fast-path branch November 2, 2026 19:20
@avgvi avgvi mentioned this pull request Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant