-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Speed up cached function access #2075
Changes from 6 commits
86780a8
014fee9
eefd9fe
6194a64
b282fe7
5b5b171
4d17add
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -224,8 +224,24 @@ def __init__(self, orig, num_args, inlineCallbacks, cache_context=False): | |
) | ||
|
||
self.num_args = num_args | ||
|
||
# list of the names of the args used as the cache key | ||
self.arg_names = all_args[1:num_args + 1] | ||
|
||
# The arg spec of the wrapped function, see `inspect.getargspec` for | ||
# the type. | ||
self.arg_spec = arg_spec | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still don't think this is used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Err, good point There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... and yet it is still here... |
||
|
||
# self.arg_defaults is a map of arg name to its default value for each | ||
# argument that has a default value | ||
if arg_spec.defaults: | ||
self.arg_defaults = dict(zip( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please can you document what this thing is and what type it has. |
||
all_args[-len(arg_spec.defaults):], | ||
arg_spec.defaults | ||
)) | ||
else: | ||
self.arg_defaults = {} | ||
|
||
if "cache_context" in self.arg_names: | ||
raise Exception( | ||
"cache_context arg cannot be included among the cache keys" | ||
|
@@ -289,18 +305,31 @@ def __get__(self, obj, objtype=None): | |
iterable=self.iterable, | ||
) | ||
|
||
def get_cache_key(args, kwargs): | ||
"""Given some args/kwargs return a generator that resolves into | ||
the cache_key. | ||
|
||
We loop through each arg name, looking up if its in the `kwargs`, | ||
otherwise using the next argument in `args`. If there are no more | ||
args then we try looking the arg name up in the defaults | ||
""" | ||
pos = 0 | ||
for nm in self.arg_names: | ||
if nm in kwargs: | ||
yield kwargs[nm] | ||
elif pos < len(args): | ||
yield args[pos] | ||
pos += 1 | ||
else: | ||
yield self.arg_defaults[nm] | ||
|
||
@functools.wraps(self.orig) | ||
def wrapped(*args, **kwargs): | ||
# If we're passed a cache_context then we'll want to call its invalidate() | ||
# whenever we are invalidated | ||
invalidate_callback = kwargs.pop("on_invalidate", None) | ||
|
||
# Add temp cache_context so inspect.getcallargs doesn't explode | ||
if self.add_cache_context: | ||
kwargs["cache_context"] = None | ||
|
||
arg_dict = inspect.getcallargs(self.orig, obj, *args, **kwargs) | ||
cache_key = tuple(arg_dict[arg_nm] for arg_nm in self.arg_names) | ||
cache_key = tuple(get_cache_key(args, kwargs)) | ||
|
||
# Add our own `cache_context` to argument list if the wrapped function | ||
# has asked for one | ||
|
@@ -341,7 +370,10 @@ def onErr(f): | |
cache.set(cache_key, result_d, callback=invalidate_callback) | ||
observer = result_d.observe() | ||
|
||
return logcontext.make_deferred_yieldable(observer) | ||
if isinstance(observer, defer.Deferred): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because some of the speed up comes from not having to bounce through all the deferred stuff (which is much more complicated than just unwrapping to get the value) at the call sites. Though we can also leave that to another PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. understood, leave it how it is |
||
return logcontext.make_deferred_yieldable(observer) | ||
else: | ||
return observer | ||
|
||
wrapped.invalidate = cache.invalidate | ||
wrapped.invalidate_all = cache.invalidate_all | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bet this will break something somewhere :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be clear: I'm not suggesting doing much about it, other than watching for breakage when it lands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest I'm concerned about this, but it makes cache hits much cheaper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably worth documenting it in a docstring.