classification
Title: Space saving step for the LRU cache
Type: resource usage Stage: resolved
Components: Library (Lib) Versions: Python 3.7
process
Status: closed Resolution:
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: rhettinger, serhiy.storchaka
Priority: low Keywords: patch

Created on 2017-01-09 16:38 by rhettinger, last changed 2018-01-29 20:49 by rhettinger. This issue is now closed.

Files
File name Uploaded Description Edit
functools_sync.diff rhettinger, 2017-01-09 16:38 Only unpack when key is not a tuple review
functools_sync2.diff rhettinger, 2017-01-09 16:40 Check int or str like the pure python code does review
Messages (4)
msg285051 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2017-01-09 16:38
Sync with the space savings optimization in the pure Python code.

I'm unsure whether the best way is to check for an exact tuple or whether to just check an exact int/str.
msg285056 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-01-09 17:13
The first patch fails with e.g. tuple subclasses.

The optimization is correct only for types not comparable with tuples. Tuple subclasses are comparable, and classes with custom __eq__ can be comparable. Thus the optimization should be used only for exact builtin types that are known not comparable with tuples. Of course it makes sense only for hashable types.

First than commit something like the second patch I would gather statistics. What are the most used types of the single positional argument of lru-cached functions? Is it worth to apply the optimization for bytes or None? Checking type in C is cheaper than in Python, we can use more types.
msg285058 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-01-09 17:28
Ah, there is a wart in the optimization in Python implementation. If call a cached function with multiple integer arguments and with equivalent float arguments, the second call will return a cached result. But if call with single integer and float arguments, both calls will be cached separately.

>>> import functools
>>> @functools.lru_cache()
... def f(*args):
...     return args
... 
>>> f(1, None)
(1, None)
>>> f(1.0, None)
(1, None)
>>> f.cache_info()
CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
>>> f.cache_clear()
>>> f(1)
(1,)
>>> f(1.0)
(1.0,)
>>> f.cache_info()
CacheInfo(hits=0, misses=2, maxsize=128, currsize=2)
msg311169 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-01-29 20:49
I've lost interest in this.
History
Date User Action Args
2018-01-29 20:49:17rhettingersetstatus: open -> closed

messages: + msg311169
stage: patch review -> resolved
2017-01-09 17:28:51serhiy.storchakasetmessages: + msg285058
2017-01-09 17:13:57serhiy.storchakasetassignee: serhiy.storchaka -> rhettinger
messages: + msg285056
2017-01-09 16:40:05rhettingersetfiles: + functools_sync2.diff
2017-01-09 16:38:21rhettingercreate