NumPy ndarray.tofile与f.write性能差异及大数据场景性能疑问
为什么ndarray.tofile比f.write慢这么多?大数据集下表现如何?
哇,这个测试结果确实有点反直觉!先结合你给出的测试代码,拆解下为什么会出现这么大的性能差异,再聊聊大数据集下的表现~
先看你的测试数据
写入测试
ndarray.tofile(file): 10.668秒
timeit.timeit("a.tofile(f)", "import numpy as np; dt=np.dtype('B'); f=open('test.x','wb'); a=np.array(range(100),dt)")
file.write(ndarray.tobytes()): 0.316秒
timeit.timeit("f.write(a.tobytes())", "import numpy as np; dt=np.dtype('B'); f=open('test.x','wb'); a=np.array(range(100),dt)")
读取测试
np.array(list(f.read()), dt): 11.544秒
timeit.timeit("a=np.array(list(f.read()),dt)", "import numpy as np; dt=np.dtype('B'); f=open('test.x','rb');")
np.fromfile(f, dt): 11.544秒
timeit.timeit("a=np.fromfile(f,dt)", "import numpy as np; dt=np.dtype('B'); f=open('test.x','rb');")
一、小数据集下性能差异的核心原因
你的测试用的是仅100个字节的极小数组,这时候两种方法的「固定开销」占比完全不同:
ndarray.tofile()每次调用时,会在C层面做一系列必要的准备工作:检查文件状态、处理跨平台字节序兼容、封装系统调用逻辑等。这些开销是固定的,当数据量极小时,固定开销直接主导了整个执行时间,导致看起来速度很慢。f.write(a.tobytes())的逻辑是先把数组转成Pythonbytes对象(小数据下这个转换几乎没开销),再调用文件的write方法。这里的主要开销是系统调用本身,而小数据下这个调用的开销远小于tofile的固定准备开销,所以整体速度快很多。
二、大数据集下的性能反转
当你处理MB级以上的大数据集时,情况会完全反过来,ndarray.tofile()会展现出明显的性能优势:
ndarray.tofile()是直接在C层面操作数组的原始内存块,不需要额外的内存复制——它会把数组在内存中的二进制数据直接写入文件,跳过了Python层面的数据转换步骤,内存和时间效率都拉满。- 而
a.tobytes() + f.write()的问题在于:tobytes()会先创建一个和数组大小完全相同的bytes对象,这相当于把数组的数据完整复制了一遍。当数据量很大时,这份内存复制的开销会急剧上升,不仅占用额外内存,还会拖慢整体写入速度。
三、关于读取测试的结果
你测试的两个读取方法耗时相同,同样是因为数据集太小:
np.array(list(f.read()), dt)需要把文件读取的字节串转换成Python列表,再逐个元素转换成numpy数组,中间有大量Python层面的循环操作,开销很高。np.fromfile(f, dt)是C层面直接读取文件并解析成数组,理论上大数据下会快很多,但小数据下它的固定准备开销和手动转换的开销抵消了,所以看起来耗时一样。
总结
- 小数据集下:
f.write(a.tobytes())更快,因为tofile的固定开销占比太高 - 大数据集下:
ndarray.tofile()性能更优,因为它避免了内存复制,直接操作原始内存
内容的提问来源于stack exchange,提问作者DarkMatterMatt
相关产品推荐
相关产品推荐

