-
Notifications
You must be signed in to change notification settings - Fork 20
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
make data classes hashable #162
Comments
I'm having a go at this. I've noticed isodatetime/metomi/isodatetime/data.py Lines 617 to 631 in 00cdbcb
While this means the class is not many lines long, it's potentially nasty as it inherits a whole bunch of unnecessary properties ( I think I ought to either reimplement the methods such as |
Hmmm, it does make sense for A bit icky but we could potentially patch the methods away: class TimeZone(Duration):
# ...
del TimeZone.to_weeks Perhaps raise an issue to address this? |
@oliver-sanders How do you profile cylc? |
Will reply on Riot, not a quick answer. |
Added proof of concept for the Duration class at #165 if you want to take a look. (Tests will be broken until all classes are taken care of) |
It looks like
We only have |
I couldn't find a reason why on that page, what's the problem? This example works for me, we cache methods in cylc-flow using from functools import lru_cache
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
@lru_cache()
def method(self, x):
return self.a == self.b == x
y = Foo(1, 2)
y.method(1)
y.method(1)
y.method(1)
y.method(2)
print(y.method.cache_info()) $ python testy.py
CacheInfo(hits=2, misses=2, maxsize=128, currsize=2 |
Sorry, wrong link. From https://stackoverflow.com/questions/33672412/python-functools-lru-cache-with-class-methods-release-object it looks like |
Dammit! Why the hell didn't they use weak references 😡, one quick look at the functools code confirmed that ignorance is indeed bliss. So it's not a really memory leak, it stores up to the number of objects you told it to. The LRU in However the better solution would involve weak references, I really don't know why def cache(func):
cache = {}
hits = 0
misses = 0
def _lru_cache(*args):
nonlocal cache, func, hits, misses, _clean, _weak_tuple
cache_args = _weak_tuple(args)
if cache_args not in cache:
misses += 1
cache[cache_args] = func(*args)
else:
hits += 1
_clean()
return cache[cache_args]
def _clean():
nonlocal cache, _is_dead
for key in list(cache):
if _is_dead(key):
cache.pop(key)
def _weak_tuple(items):
ret = []
for item in items:
try:
ret.append(weakref.ref(item))
except TypeError:
ret.append(item)
return tuple(ret)
def _is_dead(item):
for value in item:
if isinstance(value, weakref.ref) and not value():
return True
return False
def _cache_info():
nonlocal cache, hits, misses
return f'hits {hits} misses {misses} items {len(cache)}'
_lru_cache.cache_info = _cache_info
return _lru_cache
There may be alternative Good spotting @MetRonnie! |
Perhaps the biggest architectural limitation on isodatetime is the fact that the data classes (e.g. TimePoint, Duration, TimeRecurrence) are mutable objects.
They should all be immutable and hashable, this would widen the scope for caching and efficiency improvements.
The biggest barrier to achieving this are some of the methods on
TimePoint
which mutate theTimePoint
itself (e.g.to_week_date
), the easy solution is to return a new object rather than mutating the existing one.Once done we can
lru_cache
TimeRecurrence.get_is_valid
which is currently the biggest offender in Cylc.The text was updated successfully, but these errors were encountered: