-
-
Notifications
You must be signed in to change notification settings - Fork 491
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
@cached_method does not work for special methods #12601
Comments
comment:1
As discussed with Simon, I'm working on a patch for this. |
Changed upstream from Reported upstream. Little or no feedback. to none |
comment:2
Since no operators in Sage use Since I don't think I am "upstream", I think the "report upstream" field should be "Doesn't apply". |
Upstream: Reported upstream. Little or no feedback. |
comment:3
I didn't consider you "upstream" - I reported it to sage-release. I filed it as a bug because code I used in 4.8 broke with 5.0. This is also fixed by solving this underlying problem. But you're right, this is an enhancement. |
comment:4
Replying to @saraedum:
I see - or better, I didn't see: I am not regularly reading that list... Anyway. I think it would be nice to have a mechanism to make use of the cached_method decorator for magical Python methods such as |
Changed upstream from Reported upstream. Little or no feedback. to Reported upstream. No feedback yet. |
comment:7
Note to myself: Don't forget this ticket... |
comment:8
I think I found the problem. Since the special method of the class is called, the This Hence, # This is for Parents or Elements that do not allow attribute assignment:
try:
name = self._cachedfunc.__name__
except AttributeError:
name = self.__name__
try:
return (<dict>inst.__cached_methods).__getitem__(name)
except (AttributeError,TypeError,KeyError),msg:
pass and would then create a new So, a potential solution is to additionally check What I don't like about this solution is that it would involve an additional dictionary lookup, which would slow-down every call to a cached method, fortunately only in the case that the instance does not support attribute assignment. And in addition, the call to the special method will always involve running this Alternatively, one could create a special kind of cached method, specifically for special methods of new style classes whose instances allow for attribute assignment. |
Attachment: trac12601-cached_special_methods.patch.gz |
comment:9
In principle, it would be possible to change Therefore, I created a new class I also tried to tweak the case of (usual) cached methods in the case of forbidden attribute assignment. Timings and examples With the patch:
Note that the cached hash is faster than an uncached hash that returns a constant number!! Without attribute assignment (special methods can't be wrapped in Cython, so I can't wrap
Without the patch The classes and instances are defined as above. As we know, caching the hash did not work, but of course it did work on usual methods:
The timing with the possibility to assign attributes did not change (as expected):
The timings without attribute assignment did improve with my patch as well:
Conclusion I believe that my patch solves the problem and would be glad about a review :) I didn't run the full test suite yet. It could be that there is an interference with #15038, which I thus add as a dependency (it already has positive review). |
Author: Simon King |
Changed upstream from Reported upstream. No feedback yet. to Completely fixed; Fix reported upstream |
Dependencies: #15038 |
comment:10
PS: One thing I worry about is the startup time. After all, for each cached method, it is now needed to decide whether the function name starts and ends with two underscores. |
comment:11
Replying to @simon-king-jena:
If that's a problem, why not just leave them separate decorators? By the time someone is decorating a special method, they probably are doing the wrong thing or they really know what they're doing. Plus, not all Incidentally, I suspect that this will not work for cdef classes at all, due to the special way in which special methods get compiled (and the fact they end up in slots) By the way, have you done timings on
|
comment:12
Replying to @nbruin:
If that's a problem. I simply don't know yet whether it is noticeable in startup-time. If it does not create a slow-down, I think it is more convenient to have a single decorator that works for both kind of methods.
Right. However, if we are talking about a cached non-special double underscore method for an instance that allows to assign attributes, then the distinction between
So, I think it is a non-issue. But of course, we could do a look-up in a finite list of special methods. I just fear that this would create an even bigger slow-down (if there is any slow-down noticeable).
Sure. That's why I wrote "(special methods can't be wrapped in Cython, so I can't wrap In any case, cdef classes do not play totally nicely with cached methods anyway. They quite often don't allow attribute assignment, and that's why I introduced
I didn't change argument fixer here. There was some change in #15038, namely: Postpone creation of the argument fixer. I think it was #8611 and #11115 when I last worked on speeding up the argument fixer.
That's clearly for a different ticket. Actually I have played with the idea of using an
Again, that's a different ticket. |
comment:13
According to the patchbot, there is no slow-down in startup time. Hence, we might think of following your suggestion to let Recall that I am not totally convinced that a more explicit choice ("only be special for methods that are really special in Python") has any benefit. Choosing a Anyway, the patchbot also reports a failure. I could not reproduce it at home. So, I hope it is random noise. |
comment:14
The second patchbot finds that all tests pass. So, we may have detected a neutrino... |
comment:15
Review, anyone? |
comment:16
Replying to @simon-king-jena:
Only if the number of calls is significantly larger than 1.
No that should be fine. Strings like that would be fully interned, so looking Example:
Lookup is quite a bit faster than doing string manipulations:
|
comment:17
In an attempt to be a little systematic in extracting a complete list of methods that get stored in slots on a type object (those are the methods that need special attention, right?), I used
to extract the relevant lines from the definition of
Hopefully this list is complete. Is there another source of such methods? I noticed that there is a non-underscored method in there as well: Unfortunately, this list is not complete. For instance:
does not cache on
so hopefully adding those does give us a complete list. |
comment:18
Replying to @nbruin:
With the full list and with Cython, one gets
So, I disagree. If Cython is used then |
comment:19
PS: If the list only contains three elements (as in your not very realistic example), then still the string methods are faster.
PPS: When we use a frozenset instead, then using the string methods is not faster any more, even with the complete set of special attribute names.
|
comment:20
Replying to @simon-king-jena:
Right, better use sets to check membership. Also, note that I've edited #12601:comment:17 above with a list of special methods which should be usable as a lookup. It doesn't seem there's a store of these available somewhere already, so it looks like we'll have to make our own set. |
Branch: u/SimonKing/ticket/12601 |
Commit: |
New commits:
|
comment:23
I have created a git branch for this ticket, containing the original patch, removing some trailing whitespace that the patch has introduced, and then changing the detection of special method names to using a frozenset of all names that Nils has mentioned here (note that Nils presented two lists, and I combined both). Tests pass for me. Needs review, then. |
comment:24
Looks good to me. The approach seems solid. We'll see how it stands up once people start using it. |
comment:25
Please clarify whether the patch or branch should be merged. In the latter case, set the milestone to sage-6.0. Also, the Reviewer field should be filled in. |
comment:26
I hope Nils does not mind that I filled the fields for him (as he gave a positive review). |
Reviewer: Nils Bruin |
Caching does not work for the
~
operator.Also the value of
a.__invert__
changes when calling~a
.This happens because special methods are called through the type and not the actual instance for new-style classes: http://docs.python.org/release/2.7.2/reference/datamodel.html?highlight=data%20model#special-method-lookup-for-new-style-classes
As of 5.0.beta4 no operators in sage use
@cached_method
.Depends on #15038
Upstream: Completely fixed; Fix reported upstream
CC: @simon-king-jena
Component: misc
Keywords: cached_method, cache, operator, special method
Author: Simon King
Branch/Commit: u/SimonKing/ticket/12601 @
6cf1fad
Reviewer: Nils Bruin
Issue created by migration from https://trac.sagemath.org/ticket/12601
The text was updated successfully, but these errors were encountered: