Skip to content

Commit e1184e2

Browse files
authored
Merge pull request #679 from AnswerDotAI/flexicache-FIFO-to-LRU
Ensure flexicache is LRU cached
2 parents ca1b05e + 3b137ba commit e1184e2

File tree

2 files changed

+55
-34
lines changed

2 files changed

+55
-34
lines changed

fastcore/xtras.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -748,8 +748,9 @@ def is_namedtuple(cls):
748748
def flexicache(*funcs, maxsize=128):
749749
"Like `lru_cache`, but customisable with policy `funcs`"
750750
import asyncio
751+
from collections import OrderedDict
751752
def _f(func):
752-
cache,states = {}, [None]*len(funcs)
753+
cache,states = OrderedDict(), [None]*len(funcs)
753754
def _cache_logic(key, execute_func):
754755
if key in cache:
755756
result,states = cache[key]
@@ -763,7 +764,7 @@ def _cache_logic(key, execute_func):
763764
cache[key] = cache.pop(key)
764765
return result
765766
cache[key] = (newres, [f(None) for f in funcs])
766-
if len(cache) > maxsize: cache.popitem()
767+
if len(cache) > maxsize: cache.popitem(last=False)
767768
return newres
768769

769770
@wraps(func)

nbs/03_xtras.ipynb

+52-32
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@
688688
{
689689
"data": {
690690
"text/plain": [
691-
"'pip 23.3.1 from /Users/jhoward/miniconda3/lib/python3.11/site-packages/pip (python 3.11)'"
691+
"'pip 25.0.1 from /Users/drg/.venv/lib/python3.12/site-packages/pip (python 3.12)'"
692692
]
693693
},
694694
"execution_count": null,
@@ -1194,7 +1194,7 @@
11941194
{
11951195
"data": {
11961196
"text/plain": [
1197-
"Path('/Users/daniel.roy.greenfeld/fh/fastcore/fastcore')"
1197+
"Path('/Users/drg/git/fastcore/fastcore')"
11981198
]
11991199
},
12001200
"execution_count": null,
@@ -1261,7 +1261,7 @@
12611261
{
12621262
"data": {
12631263
"text/plain": [
1264-
"Path('000_tour.ipynb')"
1264+
"Path('llms.txt')"
12651265
]
12661266
},
12671267
"execution_count": null,
@@ -1440,7 +1440,7 @@
14401440
"text/markdown": [
14411441
"---\n",
14421442
"\n",
1443-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L389){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1443+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L391){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
14441444
"\n",
14451445
"#### ReindexCollection\n",
14461446
"\n",
@@ -1451,7 +1451,7 @@
14511451
"text/plain": [
14521452
"---\n",
14531453
"\n",
1454-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L389){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1454+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L391){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
14551455
"\n",
14561456
"#### ReindexCollection\n",
14571457
"\n",
@@ -1523,7 +1523,7 @@
15231523
"text/markdown": [
15241524
"---\n",
15251525
"\n",
1526-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L400){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1526+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
15271527
"\n",
15281528
"###### ReindexCollection.reindex\n",
15291529
"\n",
@@ -1534,7 +1534,7 @@
15341534
"text/plain": [
15351535
"---\n",
15361536
"\n",
1537-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L400){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1537+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L402){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
15381538
"\n",
15391539
"###### ReindexCollection.reindex\n",
15401540
"\n",
@@ -1623,7 +1623,7 @@
16231623
"text/markdown": [
16241624
"---\n",
16251625
"\n",
1626-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L404){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1626+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L406){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
16271627
"\n",
16281628
"##### ReindexCollection.cache_clear\n",
16291629
"\n",
@@ -1634,7 +1634,7 @@
16341634
"text/plain": [
16351635
"---\n",
16361636
"\n",
1637-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L404){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1637+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L406){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
16381638
"\n",
16391639
"##### ReindexCollection.cache_clear\n",
16401640
"\n",
@@ -1688,7 +1688,7 @@
16881688
"text/markdown": [
16891689
"---\n",
16901690
"\n",
1691-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1691+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L403){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
16921692
"\n",
16931693
"##### ReindexCollection.shuffle\n",
16941694
"\n",
@@ -1699,7 +1699,7 @@
16991699
"text/plain": [
17001700
"---\n",
17011701
"\n",
1702-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L401){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
1702+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L403){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
17031703
"\n",
17041704
"##### ReindexCollection.shuffle\n",
17051705
"\n",
@@ -1732,7 +1732,7 @@
17321732
{
17331733
"data": {
17341734
"text/plain": [
1735-
"['a', 'd', 'h', 'c', 'e', 'b', 'f', 'g']"
1735+
"['a', 'd', 'g', 'f', 'h', 'e', 'b', 'c']"
17361736
]
17371737
},
17381738
"execution_count": null,
@@ -1988,7 +1988,7 @@
19881988
{
19891989
"data": {
19901990
"text/plain": [
1991-
"'https://github.com/fastai/fastcore/tree/master/fastcore/test.py#L35'"
1991+
"'https://github.com/fastai/fastcore/tree/master/fastcore/test.py#L37'"
19921992
]
19931993
},
19941994
"execution_count": null,
@@ -2291,7 +2291,7 @@
22912291
"text/markdown": [
22922292
"---\n",
22932293
"\n",
2294-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L530){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2294+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L534){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
22952295
"\n",
22962296
"#### EventTimer\n",
22972297
"\n",
@@ -2302,7 +2302,7 @@
23022302
"text/plain": [
23032303
"---\n",
23042304
"\n",
2305-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L530){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2305+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L534){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
23062306
"\n",
23072307
"#### EventTimer\n",
23082308
"\n",
@@ -2336,8 +2336,8 @@
23362336
"name": "stdout",
23372337
"output_type": "stream",
23382338
"text": [
2339-
"Num Events: 3, Freq/sec: 205.6\n",
2340-
"Most recent: ▁▁▃▁▇ 254.1 263.2 284.5 259.9 315.7\n"
2339+
"Num Events: 1, Freq/sec: 155.1\n",
2340+
"Most recent: ▇▂▂▁▁ 386.7 269.9 285.5 249.6 220.0\n"
23412341
]
23422342
}
23432343
],
@@ -2416,7 +2416,7 @@
24162416
"text/markdown": [
24172417
"---\n",
24182418
"\n",
2419-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L562){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2419+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L566){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
24202420
"\n",
24212421
"#### PartialFormatter\n",
24222422
"\n",
@@ -2427,7 +2427,7 @@
24272427
"text/plain": [
24282428
"---\n",
24292429
"\n",
2430-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L562){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2430+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L566){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
24312431
"\n",
24322432
"#### PartialFormatter\n",
24332433
"\n",
@@ -2499,7 +2499,7 @@
24992499
"name": "stdout",
25002500
"output_type": "stream",
25012501
"text": [
2502-
"2000-01-01 12:00:00 UTC is 2000-01-01 22:00:00+10:00 local time\n"
2502+
"2000-01-01 12:00:00 UTC is 2000-01-01 20:00:00+08:00 local time\n"
25032503
]
25042504
}
25052505
],
@@ -2529,7 +2529,7 @@
25292529
"name": "stdout",
25302530
"output_type": "stream",
25312531
"text": [
2532-
"2000-01-01 12:00:00 local is 2000-01-01 02:00:00+00:00 UTC time\n"
2532+
"2000-01-01 12:00:00 local is 2000-01-01 04:00:00+00:00 UTC time\n"
25332533
]
25342534
}
25352535
],
@@ -2632,7 +2632,7 @@
26322632
"text/markdown": [
26332633
"---\n",
26342634
"\n",
2635-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L619){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2635+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L623){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
26362636
"\n",
26372637
"#### ContextManagers\n",
26382638
"\n",
@@ -2643,7 +2643,7 @@
26432643
"text/plain": [
26442644
"---\n",
26452645
"\n",
2646-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/xtras.py#L619){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2646+
"[source](https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py#L623){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
26472647
"\n",
26482648
"#### ContextManagers\n",
26492649
"\n",
@@ -3172,8 +3172,9 @@
31723172
"def flexicache(*funcs, maxsize=128):\n",
31733173
" \"Like `lru_cache`, but customisable with policy `funcs`\"\n",
31743174
" import asyncio\n",
3175+
" from collections import OrderedDict\n",
31753176
" def _f(func):\n",
3176-
" cache,states = {}, [None]*len(funcs)\n",
3177+
" cache,states = OrderedDict(), [None]*len(funcs)\n",
31773178
" def _cache_logic(key, execute_func):\n",
31783179
" if key in cache:\n",
31793180
" result,states = cache[key]\n",
@@ -3187,7 +3188,7 @@
31873188
" cache[key] = cache.pop(key)\n",
31883189
" return result\n",
31893190
" cache[key] = (newres, [f(None) for f in funcs])\n",
3190-
" if len(cache) > maxsize: cache.popitem()\n",
3191+
" if len(cache) > maxsize: cache.popitem(last=False)\n",
31913192
" return newres\n",
31923193
"\n",
31933194
" @wraps(func)\n",
@@ -3298,6 +3299,32 @@
32983299
" return flexicache(time_policy(seconds), maxsize=maxsize)"
32993300
]
33003301
},
3302+
{
3303+
"cell_type": "code",
3304+
"execution_count": null,
3305+
"metadata": {},
3306+
"outputs": [],
3307+
"source": [
3308+
"# demonstrate that flexicache is LRU\n",
3309+
"@flexicache(maxsize=2)\n",
3310+
"def cached_func(x): return time()\n",
3311+
"\n",
3312+
"time_1 = cached_func(1)\n",
3313+
"test_eq(time_1, cached_func(1))\n",
3314+
"\n",
3315+
"time_2 = cached_func(2)\n",
3316+
"test_eq(time_1, cached_func(1))\n",
3317+
"test_eq(time_2, cached_func(2))\n",
3318+
"\n",
3319+
"time_3 = cached_func(3) # Removes 1\n",
3320+
"\n",
3321+
"test_eq(time_2, cached_func(2)) # cache remains\n",
3322+
"test_eq(time_3, cached_func(3)) # cache remains\n",
3323+
"test_ne(time_1, cached_func(1)) # NEQ, removes 2\n",
3324+
"test_ne(time_2, cached_func(2)) # NEQ, removes 3\n",
3325+
"test_eq(cached_func(1), cached_func(1))"
3326+
]
3327+
},
33013328
{
33023329
"cell_type": "markdown",
33033330
"metadata": {},
@@ -3355,13 +3382,6 @@
33553382
"#|hide\n",
33563383
"import nbdev; nbdev.nbdev_export()"
33573384
]
3358-
},
3359-
{
3360-
"cell_type": "code",
3361-
"execution_count": null,
3362-
"metadata": {},
3363-
"outputs": [],
3364-
"source": []
33653385
}
33663386
],
33673387
"metadata": {

0 commit comments

Comments
 (0)