You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 08:06:23