循环处理335k个fits文件的脚本随运行变慢,如何优化性能?
性能优化方案
1. 核心内存占用过高问题修复
- 优化
lam_resample_dic的key生成逻辑:你当前用全数组字符串拼接生成key的方式存在两个严重问题:一是生成速度极慢,每遍历一个文件都要做全量字符串拼接运算;二是key本身长度极大,加上存储的BandResampler实例,33.5万次循环后字典会占用巨量内存。
优化方案:先判断data_s['LOGLAM']的数组长度,长度不一致直接归为不同采样配置;长度一致时,对数组做哈希运算(比如用hash(tuple(data_s['LOGLAM']))或者轻量摘要算法)生成短key,大幅降低字典的内存占用和查找开销。 - 及时释放无用内存:每次处理完
data_s的LOGLAM和FLUX字段后,主动执行del data_s销毁fits表对象,不需要等待Python自动回收;每处理1000条数据后调用一次gc.collect()主动清理内存碎片。 - 可选:如果唯一采样配置的数量远超预期,可以给
lam_resample_dic加缓存淘汰策略,比如只保留最近使用的几十到上百个BandResampler实例,避免字典无限膨胀。
2. 写入逻辑优化
你当前保持输出文件全程打开的方案优于每次写入才打开的方案,频繁开关文件会带来大量额外的IO开销,但还可以进一步优化:
- 批量写入:不要每次生成一个
photo_spec就调用一次np.savetxt,可以先攒N条(比如1000条)到一个临时列表,攒满后一次性转成二维numpy数组写入文件,能大幅降低IO操作次数,写入速度至少提升数倍。
参考代码片段:
import gc batch = [] batch_size = 1000 with open("/home/bla/Downloads/output.txt", "ab") as f: for ind, fname in enumerate(list_of_fnames): data_s = Table.read('/home/nestor/Downloads/all_eBoss_QSO/'+fname, format='fits', memmap=True) # 中间处理逻辑得到photo_spec batch.append(photo_spec) del data_s if len(batch) >= batch_size: np.savetxt(f, batch, delimiter=',', fmt='%1.4f') batch = [] gc.collect() print('num of files processed so far:', ind) # 写入剩余不足batch_size的数据 if batch: np.savetxt(f, batch, delimiter=',', fmt='%1.4f')
3. 循环效率优化
- 把
zip(list_of_fnames, range(len(list_of_fnames)))替换为enumerate(list_of_fnames),不需要额外生成range对象和做zip运算,写法更简洁效率也更高。 - 读取fits表时开启内存映射:
Table.read传入memmap=True参数,不需要把整个fits文件加载到内存,只读取需要的两列数据即可,大幅降低内存占用和读取耗时。 - 修复代码bug:你当前进度打印里的
find变量未定义,应该替换为ind,避免运行时报错。
内容的提问来源于stack exchange,提问作者NeStack
相关产品推荐
相关产品推荐

