Python 3.11.1中all()/any()性能较3.10.9下降问题咨询
Python 3.11.1中all()/any()性能下降的问题
我发现Python 3.11.1里all()和any()的实现比Python 3.10.9分别慢30%和23%,但单独判断item["id"] == match_data["id"]时,3.11.1反而快3%。以下是测试代码及结果,想请教该性能差异的原因:
测试代码
import timeit from functools import partial import platform def find_by_keys( keys: list[str], table: list[dict[str, str | int]], match_data: dict[str, str | int], ) -> dict[str, str | int] | None: for item in table: if all(item[k] == match_data[k] for k in keys): # 30% slower on 3.11 # if any(item[k] == match_data[k] for k in keys): # 23% slower on 3.11 # if item["id"] == match_data["id"]: # 3% faster on 3.11 return item return None def main(): keys: list[str] = ["id", "key_1", "key_2"] table: list[dict[str, str | int]] = [ { "id": i, "key_1": "val_1", "key_2": "val_2", } for i in range(1, 5001) ] match_data: dict[str, str | int] = { "id": 3000, "key_1": "val_1", "key_2": "val_2", } # Note: used repeat=50000 for all() calls, otherwise used repeat=500000 timeit_output = timeit.repeat( partial(find_by_keys, keys, table, match_data), repeat=50000, number=1 ) average_time = sum(timeit_output) / len(timeit_output) best_time = min(timeit_output) tps_output = 1 / average_time print(f"Python version = {platform.python_version()}") print(f"Average time = {average_time}") print(f"Best time = {best_time}") print(f"Average transactions per second = {tps_output}") if __name__ == "__main__": main()
测试结果
Python 3.10.9输出
Python version = 3.10.9 Average time = 0.0008256170657486655 Best time = 0.0007106999401003122 Average transactions per second = 1211.2152733824669
Python 3.11.1输出
Python version = 3.11.1 Average time = 0.0011819988898839802 Best time = 0.001033599954098463 Average transactions per second = 846.0244832363215
性能差异的原因分析
- 生成器迭代的固定开销:Python 3.11的核心优化是更快的字节码解释器,但
all()/any()依赖生成器表达式作为迭代源。生成器的创建、挂起和恢复操作在3.11中引入了额外的固定开销,这种开销在短迭代(比如仅3个元素的keys列表)场景下占比极高,抵消了解释器的整体优化收益。而单次字典键值比较无需生成器的迭代协议,能直接享受到3.11的解释器提速。 - all()/any()的内部实现调整:3.11对
all()和any()的底层逻辑可能做了调整,比如增加了类型检查或兼容性处理步骤。这些额外操作在处理短序列时,单位元素的开销被放大,导致整体性能不如3.10。 - 短迭代场景的开销放大效应:当迭代序列长度极短时,迭代器的启动和管理开销占总耗时的比例远高于实际元素处理的耗时。3.11中这种迭代器相关的固定开销比3.10更高,而单次比较没有这部分开销,所以呈现出相反的性能表现。
内容的提问来源于stack exchange,提问作者Onlooker2186
相关产品推荐
相关产品推荐

