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
Generic type subscription is a huge toll on Python performance #83349
Comments
Reported originally here - See details here In [4]: class Foo: pass In [6]: T = TypeVar("T") Same effect in Python 3.6 and 3.8 |
Python typing gives an order of magnitude slow down in this case |
In [12]: cProfile.run("for _ in range(100_000): Bar()") Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) In [13]: # And typing.py:865 points to In [14]: inspect.getsourcelines(Generic.__new__) |
What Python version was used for the timings? If not 3.8, please do over in 3.8. |
Sorry, you already said 3.6 and 3.8 give the same effect. But what if you add a minimal __new__() to Foo? |
Hm, here's what I measure in Python 3.8.1. (I don't use IPython or notebooks so this looks a little different.) >>> timeit.timeit('Foo()', 'class Foo: pass')
0.37630256199999934
>>> timeit.timeit('Foo()', 'class Foo:\n def __new__(cls): return super().__new__(cls)')
1.5753196039999864
>>> timeit.timeit('Foo()', 'from typing import Generic, TypeVar\nT = TypeVar("T")\nclass Foo(Generic[T]): pass')
3.8748737150000068 From this I conclude that adding a minimal __new__() method is responsible for about 4x slowdown, and the functionality in typing.py for another factor 2.5. While this isn't great I don't see an easy way to improve upon this without rewriting the entire typing module in C. (Some of this may or may not happen for PEP-604.) PS. I just realized my Python binary was built with debug options, so absolute numbers will look different (better) for you -- but relative numbers will look the same, and I get essentially the same factors with 3.9.0a1+. |
This issue came up few times before (although I can't find an issue here on b.p.o., maybe it was on typing-sig list). Although in micro-benchmarks the impact may seem big, in vast majority of applications it is rarely more that a percent or so. On the other hand, IIRC the only reason |
If that solves the perf issue I am fine with it. |
OK, here is the original issue python/typing#681. I asked the author to open an issue here instead, but likely they didn't open one. |
Thank you Guido and Ivan |
OK let’s do it. Clearly for *some* applications the overhead is significant.--Guido (mobile) |
Perhaps the check should only be done in some sort of Python development mode and off by default? |
Didn't see your last response before submitting an update. That's great you have a plan how to resolve this! Thanks again |
Should this be backported? How far back? |
Is this performance issue supposed to be fixed in 3.9? I'm still observing severe slowdown by inheriting from I'm currently adding typing to Werkzeug, where we define many custom data structures such as Here's a minimal example without Werkzeug, the results in Werkzeug are similar or worse. I'd estimate each request creates about 10 of the various data structures, which are then accessed by user code, so I simulated that by creating and iterating a list of objects. class Test:
def __init__(self, value):
self.value = value
def main():
ts = [Test(x) for x in range(10)]
sum(t.value for t in ts)
import typing
V = typing.TypeVar("V")
class Test(typing.Generic[V]):
def __init__(self, value: V) -> None:
self.value = value
def main():
ts = [Test(x) for x in range(10)]
sum(t.value for t in ts)
There is more than a 2x slowdown when using Since we currently support Python 3.6+, I probably won't be able to use generics anyway due to the performance in those versions, but I wanted to make sure I'm not missing something with 3.9. |
I don't see such a dramatic difference -- the generic version is a tad slower, but the difference is less than the variation between runs. What platform are you using? (I'm doing this on Windows.) |
I'm using Arch Linux. After your reply I tried again and now I'm seeing the same result as you, negligible difference from inheriting |
No worries. I tend to run each time it command at least three times before I trust the numbers. Professional bench markers also configure a machine without background tasks (email etc.). |
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: