[IMP] core: speed up loading of registry

The base classes of models in the registry are modified when models are
extended by inheritance.  But modifying cls.__bases__ is a costly
operation, so we manage to do it once per model when loading a registry.

Our benchmark consists in loading a registry with 296 modules.  The net
time to load the registry is 25% smaller.  In other words, the registry
loads 25% faster.  Note that the time does not include the time to load
modules themselves, which does not change.
This commit is contained in:
Raphael Collet
2021-05-06 07:20:00 +00:00
parent 3d84bb6494
commit cd12293386
2 changed files with 11 additions and 5 deletions
@@ -3086,7 +3086,7 @@ class TestSelectionOndeleteAdvanced(common.TransactionCase):
# necessary cleanup for resetting changes in the registry
for model_name in (self.MODEL_BASE, self.MODEL_REQUIRED):
Model = self.registry[model_name]
self.addCleanup(setattr, Model, '__bases__', Model.__bases__)
self.addCleanup(setattr, Model, '_BaseModel__base_classes', Model._BaseModel__base_classes)
def test_ondelete_unexisting_policy(self):
class Foo(models.Model):
+10 -4
View File
@@ -618,7 +618,7 @@ class BaseModel(metaclass=MetaModel):
ModelClass._build_model_check_base(cls)
check_parent = ModelClass._build_model_check_parent
else:
ModelClass = type(name, (BaseModel,), {
ModelClass = type(name, (cls,), {
'_name': name,
'_register': False,
'_original_module': cls._module,
@@ -636,7 +636,7 @@ class BaseModel(metaclass=MetaModel):
raise TypeError("Model %r inherits from non-existing model %r." % (name, parent))
parent_class = pool[parent]
if parent == name:
for base in parent_class.__bases__:
for base in parent_class.__base_classes:
bases.add(base)
else:
check_parent(cls, parent_class)
@@ -644,7 +644,9 @@ class BaseModel(metaclass=MetaModel):
ModelClass._inherit_module[parent] = cls._module
parent_class._inherit_children.add(name)
ModelClass.__bases__ = tuple(bases)
# ModelClass.__bases__ must be assigned those classes; however, this
# operation is quite slow, so we do it once in method _prepare_setup()
ModelClass.__base_classes = tuple(bases)
# determine the attributes of the model's class
ModelClass._build_model_attributes(pool)
@@ -701,7 +703,7 @@ class BaseModel(metaclass=MetaModel):
cls._depends = {}
cls._sql_constraints = {}
for base in reversed(cls.__bases__):
for base in reversed(cls.__base_classes):
if is_definition_class(base):
# the following attributes are not taken from registry classes
if cls._name not in base._inherit and not base._description:
@@ -2839,6 +2841,10 @@ class BaseModel(metaclass=MetaModel):
cls = type(self)
cls._setup_done = False
# changing base classes is costly, do it only when necessary
if cls.__bases__ != cls.__base_classes:
cls.__bases__ = cls.__base_classes
# reset those attributes on the model's class for _setup_fields() below
for attr in ('_rec_name', '_active_name'):
discardattr(cls, attr)