You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, functools.lru_cache implement own doubly-linked list.
But it is inefficient than OrderedDict because each link node is GC object.
So it may eat more memory and take longer GC time.
I added two private C API for OrderedDict and make lru_cache use it.
_PyODict_LRUGetItem(): Similar to PyDict_GetItemWithHash() + od.move_to_end(last=True).
_PyODict_PopItem(): Similar to odict.popitem().
Why I didn't implement C version of move_to_end() is to reduce lookup.
_PyODict_LRUGetItem(key) lookup key once while
od[key]; od.move_to_end(key) lookup key twice.
Hmm, it seems my implementation is 30% slower when many mishit scenario.
Maybe, dict is faster than OrderedDict about massive insert/discard. But I need to profile it.
On the other hand, GC speed looks about 2x faster as expected.
I found odict.pop() and odict.popitem() is very inefficient because
it look up key multiple times.
odict seems not optimized well and very slow than dict in some area...
Please stop revising every single thing you look at. The traditional design of LRU caches used doubly linked lists for a reason. In particular, when there is a high hit rate, the links can be updated without churning the underlying dictionary.
Please stop revising every single thing you look at. The traditional design of LRU caches used doubly linked lists for a reason. In particular, when there is a high hit rate, the links can be updated without churning the underlying dictionary.
I don't proposing removing doubly linked list; OrderedDict uses
doubly-linked list too, and I found no problem for most-hit scenario.
On the other hand, I found problem of OrderedDict for most mis hit
scenario.
Now I think lru_cache's implementation is better OrderedDict.
PyODict is slower than lru_cache's dict + linked list because of
historical reason (compatibility with pure Python implemantation.)
So I stop trying to remove lru_cache's own implementation.
I'll try to reduce overhead of lru_cache, by removing GC header
from link node.
Activity
methane commentedon Dec 24, 2017
Currently, functools.lru_cache implement own doubly-linked list.
But it is inefficient than OrderedDict because each link node is GC object.
So it may eat more memory and take longer GC time.
I added two private C API for OrderedDict and make lru_cache use it.
Why I didn't implement C version of move_to_end() is to reduce lookup.
_PyODict_LRUGetItem(key) lookup key once while
od[key]; od.move_to_end(key) lookup key twice.
I'll benchmark it and report result here.
methane commentedon Dec 24, 2017
Current implementation (no news entry yet):
https://github.com/methane/cpython/pull/10/files
serhiy-storchaka commentedon Dec 24, 2017
This is a duplicate of bpo-28239.
serhiy-storchaka commentedon Dec 24, 2017
Ah, sorry, you use OrderedDict instead of just ordered dict. It should have different timing and memory consumption.
methane commentedon Dec 24, 2017
Hmm, it seems my implementation is 30% slower when many mishit scenario.
Maybe, dict is faster than OrderedDict about massive insert/discard. But I need to profile it.
On the other hand, GC speed looks about 2x faster as expected.
Faster (4):
methane commentedon Dec 24, 2017
I found odict.pop() and odict.popitem() is very inefficient because
it look up key multiple times.
odict seems not optimized well and very slow than dict in some area...
I'll try to optimize it in holidays.
rhettinger commentedon Dec 24, 2017
Please stop revising every single thing you look at. The traditional design of LRU caches used doubly linked lists for a reason. In particular, when there is a high hit rate, the links can be updated without churning the underlying dictionary.
rhettinger commentedon Dec 24, 2017
FWIW, I'm the original author and designer of this code, so it would have been appropriate to assign this to me for sign-off on any proposed changes.
serhiy-storchaka commentedon Dec 24, 2017
Not me (the C implementation)? ;-)
methane commentedon Dec 25, 2017
I don't proposing removing doubly linked list; OrderedDict uses
doubly-linked list too, and I found no problem for most-hit scenario.
On the other hand, I found problem of OrderedDict for most mis hit
scenario.
Now I think lru_cache's implementation is better OrderedDict.
PyODict is slower than lru_cache's dict + linked list because of
historical reason (compatibility with pure Python implemantation.)
So I stop trying to remove lru_cache's own implementation.
I'll try to reduce overhead of lru_cache, by removing GC header
from link node.
[-]Make OrderedDict can be used for LRU from C[/-][+]Reduce lru_cache memory overhead.[/+]methane commentedon Dec 25, 2017
PR-5008 benchmark:
serhiy-storchaka commentedon Dec 25, 2017
LGTM.
methane commentedon Dec 25, 2017
New changeset 3070b71 by INADA Naoki in branch 'master':
bpo-32422: Reduce lru_cache memory usage (GH-5008)
3070b71