Python list与array迭代性能差异异常的原因探究
嘿,我之前做性能测试的时候也碰到过这种理论和实际不符的情况,结合你的场景,大概有这几个原因能解释为啥结果和预期相反:
超大数据量下,缓存优势被彻底抹平
虽然array.array是同类型连续内存,理论上缓存命中率更高,但你用的是2^30个整数——这数据量差不多要占1GB左右的内存(按每个int4字节算),普通机器的L3缓存也就几GB,这么大的数据直接把缓存打满了,不管是list还是array,迭代的时候都得频繁从主存甚至交换区读数据,原本的缓存优势根本发挥不出来。而且别忘了,Python的list底层是动态数组(不是链表,多亏Duncan的纠正!),本身的内存布局也是连续的,在这种极端数据量下,两者的内存访问模式差异被弱化了。Python解释器对list的迭代优化更到位
CPython对list的迭代有专门的底层优化,比如迭代时可以直接访问底层的对象指针数组,几乎没有额外开销;而array.array迭代的时候,每次都要把C层面的基本类型(比如int)转换成Python的int对象,这个转换过程在大规模迭代时会累积出不小的开销。换句话说,list存的本身就是Python对象,迭代直接用就行;array存的是原生类型,每次迭代都要“包装”成Python对象,反而慢了。测试细节可能影响了结果
你得确认测试代码是不是把数据生成的时间排除在外了?比如如果每次timeit循环都重新生成array,那类型转换的时间会被算进去,这肯定会拖慢array的速度。正确的做法应该是先生成好list和array,再单独测试迭代的时间,比如:import timeit import array import random # 提前生成数据,避免生成开销干扰测试 sample_size = 2**30 random_list = [random.randint(0, 100) for _ in range(sample_size)] random_array = array.array('i', random_list) # 测试迭代(用sum来模拟迭代操作) list_iter_time = timeit.timeit(lambda: sum(random_list), number=5) array_iter_time = timeit.timeit(lambda: sum(random_array), number=5) print(f"List迭代耗时: {list_iter_time:.2f}s") print(f"Array迭代耗时: {array_iter_time:.2f}s")另外,这么大的数据量,单次测试的波动会很大,多跑几次取平均会更准确。
如果想看到array的性能优势,可以试试小数据量(比如2^20),这时候缓存能正常工作,array的连续内存优势就会体现出来,迭代速度应该会比list快。或者测试一些不需要频繁转换Python对象的操作,比如直接用C扩展处理array里的原生数据,那性能差距就明显了。
内容的提问来源于stack exchange,提问作者moo

