You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Attribute cache silently disabled after 1000 class edit, leading to poor performance #156339
After the changes from #114900 modifying a class more than 1000 times causes the attribute cache to be permanently disabled for that class. This was done to solve a crash when a class is modified more than 2**32 times ( #113462 )
It seems this number (1000) is too low for some real case applications.
I initially observed this as a ~50% performance regression in ERP5 performance tests when updating from python3.11 to python3.13. ERP5 is an application where classes are generated dynamically based on some configuration and some classes are modified more than 1000 times in the "normal" generation process.
This seems to also affect odoo, another ERP application, for this they resorted to using ctypes to reset the class version attribute ( odoo/odoo#275640 )
My suggestion would be to use a much higher number before disabling the cache, 1000 is low.
Thank you. I tried running a patched interpreter with 10 000 instead of 1000 and it was enough for my case, but I suspect there can even be cases with more than 10 000 edits.
If the original problem starts with 2**31, maybe the limit can be set to something much higher, would something like 2**30 be possible ?
maybe the limit can be set to something much higher, would something like 2**30
The sum of all modifications for all classes should not reach 2**32.
Allowing 2**30 for a single class could be broken by 4 classes.
I understand why reloading a model would make many changes, but why the interleaved attribute loads?
Typically, how many loads occur between each change to the class?
I'm actually reluctant to increase the number much, for internal reasons to do with detecting the difference between cache misses due to polymorphism vs stale version numbers.
What we could do, is add a counter that tracks the number of times we want to update the version number, and only update the version number when that reaches the number of versions used. Instead of N changes before the cache stopped working it would be N*(N-1)/2 changes.
That should allow about 500k version changes, for N=1000, at the cost of slower look ups for the first several lookups after a change to the class.
For a class that makes 1000 changes, it would take about 50 lookups before the cache kicks in after the 1000th change/load pair.
I understand why reloading a model would make many changes, but why the interleaved attribute loads?
Typically, how many loads occur between each change to the class?
with this approach, there is no load so the version is not increased. Building the class would also probably be slightly faster because it would not rebuild the cache in each loop, so I feel it's generally good if I can change my code like this. Thank you for helping me realize this, I will try this in the next days.
Still, from this experience, I feel this change of disabling the cache after 1000 class modifications is not ideal, for users it manifests as a performance degradation and the root cause is hard to find. I still have the intuition that it could be increased a bit.
Activity
StanFromIreland commentedon Aug 25, 2026
CC @markshannon and @Fidget-Spinner
markshannon commentedon Aug 26, 2026
The limit (1000) was chosen quite arbitrarily.
What limit would be sufficient for your use case?
perrinjerome commentedon Aug 26, 2026
Thank you. I tried running a patched interpreter with 10 000 instead of 1000 and it was enough for my case, but I suspect there can even be cases with more than 10 000 edits.
If the original problem starts with
2**31, maybe the limit can be set to something much higher, would something like2**30be possible ?markshannon commentedon Aug 26, 2026
The sum of all modifications for all classes should not reach
2**32.Allowing
2**30for a single class could be broken by 4 classes.I understand why reloading a model would make many changes, but why the interleaved attribute loads?
Typically, how many loads occur between each change to the class?
I'm actually reluctant to increase the number much, for internal reasons to do with detecting the difference between cache misses due to polymorphism vs stale version numbers.
What we could do, is add a counter that tracks the number of times we want to update the version number, and only update the version number when that reaches the number of versions used. Instead of N changes before the cache stopped working it would be
N*(N-1)/2changes.That should allow about 500k version changes, for N=1000, at the cost of slower look ups for the first several lookups after a change to the class.
For a class that makes 1000 changes, it would take about 50 lookups before the cache kicks in after the 1000th change/load pair.
perrinjerome commentedon Aug 28, 2026
The simplified pattern is something like this:
so each
hasattrperforms a load and we have a load directly after each class modification.I realize today I can probably just rewrite this pattern to:
with this approach, there is no load so the version is not increased. Building the class would also probably be slightly faster because it would not rebuild the cache in each loop, so I feel it's generally good if I can change my code like this. Thank you for helping me realize this, I will try this in the next days.
Still, from this experience, I feel this change of disabling the cache after 1000 class modifications is not ideal, for users it manifests as a performance degradation and the root cause is hard to find. I still have the intuition that it could be increased a bit.