多父类继承的属性读取性能影响及性能衰减趋势探究
多父类继承的属性读取性能影响及性能衰减趋势探究
我一直在研究一种超宽泛的继承结构对性能的影响,具体的测试步骤如下:
- 先准备260个不同的属性名,范围是
a0到z9 - 创建260个类,每个类仅包含一个唯一命名的属性;再创建一个继承自这260个类的聚合类
- 创建130个类,每个类包含2个唯一命名的属性;同样创建一个继承自这130个类的聚合类
- 按照这个逻辑继续拓展测试:52个类(每个含5个属性)、26个类(每个含10个属性),以及一个包含全部260个属性的单一类
- 为上述5个类各创建一个实例,然后分别测量读取并累加所有260个属性的耗时
我完成了250万次属性读取的平均性能测试,测试过程中还打乱了不同的读取顺序,最终得到的结果如下:
From260: 2.48 From130: 1.55 From52: 1.22 From26: 1.15 AllInOne: 1.00
这些数据看起来能用线性回归拟合,但实际上并不完全匹配。而且不管测试规模、读取顺序怎么调整,这个性能关联关系都稳定存在。
![线性关系拟合图]
后来我尝试用二次多项式或者指数模型去拟合数据,贴合度有所提升,但依然没有达到完全清晰匹配的程度。
![二次/指数拟合对比图]
现在我有个核心疑问:当父类的数量大幅增加时,性能衰减会呈现线性趋势,还是非线性趋势?
为了进一步探究这个问题,我更新了测试代码,覆盖了更多不同的子类组合(最多到2310个父类):
from time import time TOTAL_ATTRS = 2310 # Create attribute names "a0000" through "a2309" attr_names = [f"a{i:04d}" for i in range(TOTAL_ATTRS)] # Map each attribute to a default value (1..2310) all_defaults = {name: i + 1 for i, name in enumerate(attr_names)} # The provided factors of 2310 factors = [1, 2, 3, 5, 6, 7, 10, 11, 14, 15, 21, 22, 30, 33, 35, 42, 55, 66, 70, 77, 105, 110, 154, 165, 210, 231, 330, 385, 462, 770, 1155, 2310] # Build a dictionary mapping each factor to a composite class. # For factor f, create f subclasses each with (2310 // f) attributes, # then create a composite class inheriting from all f subclasses. composite_classes = {} for f in factors: group_size = TOTAL_ATTRS // f subclasses = [] for i in range(f): group = attr_names[i * group_size:(i + 1) * group_size] group_defaults = {name: all_defaults[name] for name in group} subclass = type(f"Sub_{f}_{i}", (object,), group_defaults) subclasses.append(subclass) composite_classes[f] = type(f"From_{f}", tuple(subclasses), {}) iterations = range(0, 1_000) for n, c in composite_classes.items(): i = c() t = time() for _ in iterations: for a in attr_names: getattr(i, a) print(f"Inheriting from {n} subclasses: {time()-t:.3f}s")
新的测试结果显示,性能衰减趋势看起来更接近线性,但数据中出现了一些奇怪的“平台台阶”:
![线性拟合下的数据点图]
![二次拟合下的数据点图]
备注:内容来源于stack exchange,提问作者Phrogz




