Astropy中get_body高频调用性能优化问题求助
优化Astropy中高频调用get_body的性能问题
问题背景
使用Astropy的get_body函数时,采用NASA de430星历,首次调用因加载星历文件速度较慢,后续调用虽有所加快,但高频调用导致整体耗时累积严重。希望找到优化方案:
- 是否可通过降低精度需求(仅需1位小数)提升速度?尝试过体积更小的de432s星历,无性能提升。
- 是否支持向量化调用,传入天体列表批量获取位置?
代码示例
from time import perf_counter from astropy.coordinates import EarthLocation, solar_system_ephemeris, get_body from astropy.time import Time DATE = "2022-08-04 12:00" solar_system_ephemeris.set('de430') loc = EarthLocation(0, 0, 0) time = Time(DATE) # 首次调用单独计时 start = perf_counter() mars = get_body("mars", time, loc) print(perf_counter() - start) start = perf_counter() jupiter = get_body("jupiter", time, loc) saturn = get_body("saturn", time, loc) pluto = get_body("pluto", time, loc) mars = get_body("mars", time, loc) jupiter = get_body("jupiter", time, loc) saturn = get_body("saturn", time, loc) pluto = get_body("pluto", time, loc) mars = get_body("mars", time, loc) jupiter = get_body("jupiter", time, loc) saturn = get_body("saturn", time, loc) pluto = get_body("pluto", time, loc) mars = get_body("mars", time, loc) jupiter = get_body("jupiter", time, loc) saturn = get_body("saturn", time, loc) pluto = get_body("pluto", time, loc) moon = get_body("moon", time, loc) venus = get_body("venus", time, loc) sun = get_body("sun", time, loc) mars = get_body("mars", time, loc) sun = get_body("sun", time, loc) moon = get_body("moon", time, loc) venus = get_body("venus", time, loc) sun = get_body("sun", time, loc) moon = get_body("moon", time, loc) venus = get_body("venus", time, loc) sun = get_body("sun", time, loc) moon = get_body("moon", time, loc) jupiter = get_body("jupiter", time, loc) saturn = get_body("saturn", time, loc) sun = get_body("sun", time, loc) moon = get_body("moon", time, loc) jupiter = get_body("jupiter", time, loc) saturn = get_body("saturn", time, loc) print(perf_counter() - start)
输出结果
0.853644288000396 0.45204837000019324
已尝试的临时方案(UPDATE 2)
通过缓存装饰器封装get_body,减少重复调用的计算开销:
@cache def get_planet(body, time, location=None, ephemeris=None): return get_body(**locals())
- Python 3.9+可用
@cache,无缓存上限且速度略快于@lru_cache;若需限制缓存大小,可改用@lru_cache(maxsize=N)。
进一步优化方案
1. 批量获取天体位置(替代向量化调用)
get_body不支持直接传入天体列表,但可自行封装批量处理函数,减少内部重复初始化开销。例如:
def get_bodies(bodies, time, location=None): body_positions = {} for body in bodies: body_positions[body] = get_body(body, time, location) return body_positions # 使用示例 target_bodies = ["mars", "jupiter", "saturn", "pluto", "moon", "venus", "sun"] positions = get_bodies(target_bodies, time, loc) # 后续直接从positions字典中取值,无需重复调用get_body
2. 精度优化说明
降低输出精度(如保留1位小数)无法提升计算速度:星历计算过程始终使用星历文件的高精度数据,仅最后对结果做截断处理,计算复杂度不变。因此该思路不可行。
3. 预加载星历文件
首次调用慢是因为星历文件加载到内存的过程,可在程序启动阶段预加载星历,避免后续重复加载:
from astropy.coordinates import solar_system_ephemeris, get_body from astropy.time import Time # 启动时预加载de430星历 solar_system_ephemeris.set('de430') # 触发星历加载,后续调用无需重复加载 _ = get_body("sun", Time.now())
4. 缓存进阶优化
- 若
location固定,可将其设为函数默认参数,减少缓存键的维度,提升缓存命中效率:
from functools import cache fixed_loc = EarthLocation(0, 0, 0) @cache def get_planet(body, time): return get_body(body, time, fixed_loc)
- 若使用
@lru_cache,根据常用天体和时间的数量设置合理的maxsize,平衡内存占用与缓存效率。
5. 向量化时间处理
若需处理多个时间点的天体位置,直接传入Time数组,get_body支持向量化输入,一次调用完成多时间点计算,比循环调用效率更高:
# 多个时间点 times = Time(["2022-08-04 12:00", "2022-08-05 12:00", "2022-08-06 12:00"]) # 一次调用获取所有时间点的火星位置 mars_multi_pos = get_body("mars", times, fixed_loc)
内容的提问来源于stack exchange,提问作者astroboy
相关产品推荐
相关产品推荐

