Pydantic v2 significantly slower than v1 #6748
Replies: 12 comments 6 replies
-
I'm afraid there's not really anything we can tell from that flamegraph. Constructing models can be slower in some cases with Pydantic V2, it's validation that should be much faster with V2. However constructing models shouldn't take 0.8s unless there are a very large number. Without code to review, I can't really be more helpful than that. some guesses at things that could make building models slow (only guesses since I can't see the code!):
Other than that, hard to say - if you can share the flamegraph but not the code, please share the full HTML flamegraph so we can read the method names etc. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the quick reply! |
Beta Was this translation helpful? Give feedback.
-
might be related to #6768. |
Beta Was this translation helpful? Give feedback.
-
Thanks @samuelcolvin , definitely looks related. I also noted the high _walk count |
Beta Was this translation helpful? Give feedback.
-
#6823 might help you. |
Beta Was this translation helpful? Give feedback.
-
I have the same problem on armv7 (where it's slowdown is relevant and noticeable) and could provide a code-base that consists mostly of nested pydantic-models. I've read the issue #6768 with fastapi and just wanted to provide an example without it. Our datalib-startup slowed down >60% just by switching to pydantic v2. used software:
How the results were obtained: sudo python3 -X importtime -c 'from shepherd_core.data_models.task import EmulationTask' 2> importtime.log
|
Beta Was this translation helpful? Give feedback.
-
I am a user of githubkit, which uses pydantic under the hood. It's gotten so slow (and memory hungry!) with pydantic v2 that we can't update, as we're running githubkit on airflow, which for every task executes a new python process, having a 20+sec startup overhead (for a 5sec task) is unacceptable. Is there some way to cache the built models, so they don't have to be re-parsed? As those models only change on githubkit version upgrades, I'd ideally like to skip almost all the CPU usage that's done, and just load the parsed information from disk. |
Beta Was this translation helpful? Give feedback.
-
I've been conducting research on the initial startup duration of a simple Telegram echo-bot created with aiogram. I observed that it requires approximately 2200ms to initiate. This is notably longer compared to a functionally equivalent bot developed using pyTelegramBotAPI, which starts in just about 100ms. Upon further analysis, I discovered that the primary factor contributing to this extended startup time in the aiogram version is Pydantic. The models used in aiogram are quite extensive and their initialization seems to be a time-consuming process. Cold starts in serverless chatbots cause significant response delays, adversely affecting user experience and scalability. Minimizing these start-up times is crucial for maintaining efficient, cost-effective, and responsive bot interactions. |
Beta Was this translation helpful? Give feedback.
-
in my experience with complex jscon schema validation, i've always found that a "precompiling" or "codegen" step can often help. perform all the load-time class precreation once, and then take the compiled .py file containing "flat" classes that can validate, etc. ie: an optional precompiler could vastly speed up large, complex codebases. if someone has an example of a large, complex set of pydantic models that take a long time to load, i could try my hand at writing a pydantic compiler |
Beta Was this translation helpful? Give feedback.
-
Noticing this on my side as well. MVP below. Just importing FastAPI import time
import cProfile, pstats, io
from pstats import SortKey
def test_importing():
pr = cProfile.Profile()
pr.enable()
current_timep = time.time()
import fastapi
end_time = time.time()
pr.disable()
s = io.StringIO()
sortby = SortKey.CUMULATIVE
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print(s.getvalue())
print(f"Time taken: {end_time - current_timep}")
test_importing() Testing with
Testing with
The |
Beta Was this translation helpful? Give feedback.
-
Is there a plan to increase v2 performance here? It is still an order of magnitude slower than v1 from us, preventing us from upgrading. |
Beta Was this translation helpful? Give feedback.
-
Indeed, we definitely want to improve the import time and model build time in v2. This will increasingly be a priority for us. I'll work on some concrete plans for improvements in the coming weeks and update our roadmap! |
Beta Was this translation helpful? Give feedback.
-
I can't post the code as it's internal, but I'll try my best to describe and provide what information I can.
We have a heavily nested, big object. Some of the child objects have some custom validators, and I believe also all if not all custom objects in the model inherit from BaseModel.
After working through all the breaking changes in v2, running the same code gives me a significantly higher runtime than with v1 - around two times slower, depending on what exactly I do.
From trying some things it looks like the imports are slower, as I'm running a (typer based) CLI which takes around 0.8 seconds for
--help
in v1 and 1.9s in v2. It doesn't initialize the giant object, but does import it.I'm not an expert on flamegraphs but from what I can see v2 has significantly more calls.
v1
v2
I'm trying to figure out how to best approach this to further test what exactly takes longer. Since I haven't done any significant changes to the code I'd expect it to be at the very least on par with v1.
Beta Was this translation helpful? Give feedback.
All reactions