-
-
Notifications
You must be signed in to change notification settings - Fork 30.6k
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
Using multiple comparison operators can cause performance issues #89705
Comments
For example: def f(x):
return 1 < x < 3 will be slower than: def f(x):
return 1 < x and x < 3 The first function will generate following bytecode:
Performs unnecessary stack operations: duplicates x, rotates 3 items for no reason, then re-rotates 2 items and pops a value. This is fine if the value in the middle was more complex and needed to be duplicated rather than recalculated, which would be definitely slower, but for simpler values like names or constants, it's actually bad. The bytecode for the first function should look the same as second one which is:
|
The PR changes behavior slightly: def f():
class A:
def __lt__(self, other):
nonlocal x
x += 100
return True
a = A()
x = 1
print(a < x < 10)
x = 1
print(a < x and x < 10) ### Before ###
>>> f()
True
False
### After ###
>>> f()
False
False So strictly speaking, this would be backwards-incompatible. But morally, I am not totally sure. |
I think Dennis's example is fatal: from section 6.10 ("Comparisons"): """ So doing LOAD_FAST twice on x (in |
Agree with Tim. The idea of optimizing stack manipulation operations for constants is interesting, but is it common enough case to justify the compiler complication? See also rejected bpo-27236. |
https://bugs.python.org/issue47221 was opened as a duplicate of this. Unless there are any new ideas for getting around the concerns here, I think this can be closed. |
I came here from bpo-47221. If I am reading this correctly, it concerns me that stack operations (which should be fast) are apparently slow? If we can't reduce the number of stack operations, can we speed them up? |
For reference, chaining is about 1.18x slower in this microbenchmark on GCC: ./python -m pyperf timeit -s "x = 100" "if 10 < x < 30: print('no')" --duplicate=10 For a related case, in #75153, the bytecode generate by "a, b = a0, b0" was changed. I wonder if the same argument applies here: maybe @akuvfx's PR could be altered to use LOAD_FAST twice for each variable *only* if everything in sight is the result of a LOAD_FAST or a LOAD_CONST. My example above uses a LOAD_DEREF, so its behavior could remain unchanged. The argument that this would within the language spec is maybe a little bit more dubious than the "a, b = a0, b0" case though, since custom Thoughts? |
Closing since, unfortunately, the proposed optimization is not safe. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: