Skip to content

Ensure flexicache is LRU cached #679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 5, 2025
Merged

Ensure flexicache is LRU cached #679

merged 2 commits into from
May 5, 2025

Conversation

pydanny
Copy link
Contributor

@pydanny pydanny commented May 2, 2025

Originating ticket: #678

Problem

The Python docs say that dict.popitem is LIFO, which means it is Last In First Out. That is the opposite of FIFO, which is part of the algorithm often used in LRU (Least Recently Used).

Reference: https://docs.python.org/3/library/stdtypes.html#dict.popitem

Solution

Since the cache is constantly being popped and reset, treat the order of the cache keys as an iterator and pick the first cache key set. To do this we just call the next command once on iter(cache).

if len(cache) > maxsize: del cache[next(iter(cache))]

Tests

As cache invalidation is hard, new tests are added to flexicache that document cache invalidation and resetting.

Alternative approach: OrderedDict

collections.OrderedDict has a popitem() method with a last boolean that replicates our design, as show in the code example below:

cache = OrderedDict()
...
if len(cache) > maxsize: cache.popitem(last=False)

I rejected this approach because it adds an extra import and cache.popitem() is probably a very tiny bit slower than del cache[next(iter(cache))]. However, this approach is arguably more clear. In any case, I'm not opposed to changing out the current solution for the one presented here.

@pydanny pydanny changed the title Make flexicache LRU instead of what is either FIFO or LIFO Ensure flexicache is LRU May 2, 2025
@pydanny pydanny changed the title Ensure flexicache is LRU Ensure flexicache is LRU cached May 2, 2025
@jph00
Copy link
Contributor

jph00 commented May 3, 2025

Good find @pydanny, thanks! Let's use the OrderedDict approach, since we value simplicity most highly. BTW looking at imports, I see that asyncio is imported in that function and not used, so perhaps replace it with the collections import?

@jph00
Copy link
Contributor

jph00 commented May 3, 2025

Oh BTW don't forget nbdev_clean. Otherwise the diffs are hard to read in PRs.

@pydanny
Copy link
Contributor Author

pydanny commented May 4, 2025

I switched the PR to use the OrderedDict approach. As for the use of asyncio, I moved it out of the decorator and to the initial module imports. It is used in async_wrapper of flexicache.

Ran nbdev_clean but it still looks messy. 😞

@jph00
Copy link
Contributor

jph00 commented May 4, 2025

Oh sorry you're right I didn't see asyncio being used at the bottom there! OK in that case you should put it back where it was -- in fastcore.xtras we prefer to only import rarely used modules if/when they're actually used. You should also only import collections inside the function for the same reason. (And thank you, the diff is much cleaner and easier to read than before cleaning :) )

@pydanny pydanny force-pushed the flexicache-FIFO-to-LRU branch from f457b99 to 3b137ba Compare May 4, 2025 22:42
@pydanny pydanny marked this pull request as ready for review May 4, 2025 22:55
@pydanny
Copy link
Contributor Author

pydanny commented May 4, 2025

Why are all the tests now passing on GitHub?

I was stumped by the failing test that had emerged, being unable to replicate it locally. Here is the failing command:

nbdev_test --flags '' --n_workers 3 --pause 1.5 --file_re "[0-9][0-1].*"

Now having moved the imports to within the function all the tests are now passing on GitHub. Why is that the case?

@jph00 jph00 merged commit e1184e2 into main May 5, 2025
14 checks passed
@jph00
Copy link
Contributor

jph00 commented May 5, 2025

I don't know - I didn't see the failing tests so can't really guess. But glad it's working now :)

@jph00 jph00 added the bug Something isn't working label May 5, 2025
@pydanny
Copy link
Contributor Author

pydanny commented May 5, 2025

I still can't replicate it locally. For now I'm going to consider it a temporary GitHub problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants