类内读取大文件耗时远超普通代码的原因咨询
类内读取大文件耗时远超普通代码的原因咨询
嘿,我碰到一个特别费解的问题,想请大家帮忙分析下:同样是用一模一样的循环逻辑读取同一个大文本文件的指定位置内容,放在类的方法里执行的耗时居然比直接在脚本里写代码慢了好几万倍,实在搞不明白差异出在哪,麻烦帮忙看看!
先贴一下我的测试代码和运行结果:
类内实现的代码及运行结果
import timeit fn = "some-large-file.txt" pos = 2434735976 class TestCase: def __init__(self, filename): self.filename = filename self.content = "" def read_file(self, start): self.readstart = start with open(self.filename, "r") as f: f.seek(self.readstart) line = f.readline() while line: self.content += line.strip() line = f.readline() if line.strip().startswith('>'): return timeit_start = timeit.default_timer() a = TestCase(fn) a.read_file(pos) print(len(a.content)) timeit_stop = timeit.default_timer() print('Elapsed time: ', timeit_stop - timeit_start)
运行输出:
90338456 Elapsed time: 31628.955818721
普通脚本实现的代码及运行结果
timeit_start = timeit.default_timer() s = '' with open(fn, "r") as f: f.seek(pos) line = f.readline() while line: s += line.strip() line = f.readline() if line.strip().startswith('>'): break print(len(s)) timeit_stop = timeit.default_timer() print('Elapsed time: ', timeit_stop - timeit_start)
运行输出:
90338456 Elapsed time: 1.233782830000564
我的运行环境是Jupyter,Python 3.8.10,IPython 8.12.2。
想请教大家,这种巨大的时间差异到底是怎么来的?有没有办法优化类内的实现,让它的速度和普通版本差不多?
原因分析及优化方案
哈哈,这个问题我之前也踩过坑!核心原因其实是循环中访问实例属性和局部变量的速度差异:
- 在普通脚本里,你用局部变量
s做字符串拼接,Python访问局部变量的速度极快——它存在栈帧的局部变量表中,直接通过索引就能获取,几乎没开销。 - 而在类方法里,你每次拼接的是实例属性
self.content,访问它需要先找到self实例,再在它的__dict__字典里做哈希查找(或者走属性继承链),单次开销看似微小,但循环执行几百万次后,累计的开销就会被放大到离谱的程度,这就是耗时差几万倍的根源。
优化起来很简单,先改用局部变量完成拼接,最后再把结果赋值给实例属性就行:
def read_file(self, start): self.readstart = start # 先用局部变量暂存拼接结果 temp_content = "" with open(self.filename, "r") as f: f.seek(self.readstart) line = f.readline() while line: temp_content += line.strip() line = f.readline() if line.strip().startswith('>'): break # 最后一次性赋值给实例属性 self.content = temp_content
改完后你再测测,耗时应该会和普通脚本版本差不多!另外补充个小优化:不管是局部还是实例属性,循环里用+=拼接字符串本来就不算最优(每次都会生成新字符串),如果想进一步提速,可以用io.StringIO来做拼接,速度会更快,但先解决属性访问的问题就已经能搞定绝大部分耗时差异啦。
备注:内容来源于stack exchange,提问作者user1491229
相关产品推荐
相关产品推荐

