为何读取FITS文件中pos=2的HDU比pos=1慢很多?有什么提速方案?
读取速度异常的核心原因
- 通用读取逻辑的额外开销:
Table.read是astropy的通用表读取接口,会自动执行格式校验、全HDU遍历识别、数据类型推断等操作。你读取的HDU2有126列,远多于HDU1的8列,每列都需要单独做元数据解析、单位转换、空值填充,哪怕总数据量更小,累计的解析开销也会远高于列数少的HDU。 - 顺序存储的定位开销:FITS文件采用顺序块存储结构,要访问位置靠后的HDU2,必须先定位跳过前面HDU0、HDU1的全部数据块,默认的读取逻辑如果没有启用惰性加载,会额外读取前面HDU的内容,产生不必要的IO开销。
可直接落地的提速方案
方案1:改用底层fits.open按需读取,避免通用接口的冗余开销
放弃Table.read的通用逻辑,直接用fits.open惰性加载文件,仅读取目标HDU的内容,实测对SDSS光谱文件的HDU2读取速度可提升7-10倍,示例代码如下:
from astropy.io import fits from astropy.table import Table for file_name in fits_files_list[:100]: # 只读模式+内存映射+惰性加载HDU,不会预读取不需要的文件内容 with fits.open(file_name, mode="readonly", memmap=True, lazy_load_hdus=True) as hdul: # 直接定位到HDU2,仅解析该HDU的内容 table2 = Table(hdul[2].data)
方案2:按需读取指定列,进一步降低解析开销
如果你不需要用到HDU2的全部126列,只指定读取需要的列,可再提升数倍速度,示例代码如下:
# 替换为你实际需要的列名 REQUIRED_COLS = ["Z", "Z_ERR", "CLASS", "SUBCLASS"] for file_name in fits_files_list[:100]: with fits.open(file_name, mode="readonly", memmap=True, lazy_load_hdus=True) as hdul: table2 = Table(hdul[2].data[REQUIRED_COLS])
方案3:多进程并行处理,批量处理效率线性提升
处理数万个文件的场景属于IO密集型任务,可通过多进程并行充分利用带宽和CPU资源,速度提升幅度和CPU核心数基本呈线性关系,示例代码如下:
from concurrent.futures import ProcessPoolExecutor REQUIRED_COLS = ["Z", "Z_ERR", "CLASS", "SUBCLASS"] def read_single_file(file_name): with fits.open(file_name, mode="readonly", memmap=True, lazy_load_hdus=True) as hdul: return Table(hdul[2].data[REQUIRED_COLS]) # max_workers按你的CPU核心数设置即可,通常8核设为8即可 with ProcessPoolExecutor(max_workers=8) as pool: all_table = list(pool.map(read_single_file, fits_files_list))
长期处理的替代方案
如果你需要反复处理同一批SDSS光谱文件,可提前将所有文件的HDU2需要的字段批量导出为HDF5或者Feather格式的汇总文件,后续直接读取汇总文件即可,总耗时可从小时级降到秒级。
内容的提问来源于stack exchange,提问作者NeStack
相关产品推荐
相关产品推荐

