我有一段代码,可以使用Skyfield计算一些卫星和行星的位置。为了清晰起见,我使用Pandas DataFrame作为位置和相应时刻的容器。我想并行计算,但总是得到相同的错误:TypeError: can't pickle Satrec objects。测试了不同的并行器,如Dask、pandarallel、swifter和Pool.map()。
需要并行化的代码示例:
def get_sun_position(self, row):
t = self.ts.utc(row["Date"]) # from skyfield
pos = self.earth.at(t).observe(self.sun).apparent().position.m # from skyfield, error is here
return pos
def get_sat_position(self, row):
t = self.ts.utc(row["Date"]) # from skyfield
pos = self.sat.at(t).position.m # from skyfield, error is here
return pos
def get_positions(self):
self.df["sat_pos"] = self.df.swifter.apply(self.get_sat_position, axis=1) # all the parallelization goes here
self.df["sun_pos"] = self.df.swifter.apply(self.get_sun_position, axis=1) # and here
# the same implementation but using dask
# self.df["sat_pos"] = dd.from_pandas(self.df, npartitions=4*cpu_count())\
# .map_partitions(lambda df : df.apply(lambda row : self.get_sat_position(row),axis=1))\
# .compute(scheduler='processes')
# self.df["sun_pos"] = dd.from_pandas(self.df, npartitions=4*cpu_count())\
# .map_partitions(lambda df : df.apply(lambda row : self.get_sun_position(row),axis=1))\
# .compute(scheduler='processes')为了避免泡菜,我尝试像这个serializers=['dask', 'pickle']一样手动设置serializaton,但无济于事。
据我所知,Skyfield使用的是sgp4,它包含了Satrec类。
我想知道是否有一些方法可以并行化这个.apply()。或者我根本不应该尝试Skyfield函数来进行并行处理?
发布于 2020-04-02 21:14:13
遗憾的是,您用来使计算并行的所有机制都是通过创建另一个进程,然后将计算中涉及的所有对象的副本发送到另一个进程来实现的- Satrec对象是用C++编写的,而不是Python语言,以提高计算速度,并且C++对象没有本机方法将自己“序列化”成字节,以便传输到另一个进程。(Python对象内置了该功能。)
你有没有分析你的代码,看看最昂贵的步骤是什么?我的猜测是,你的大部分费用是在太阳计算中,因为为了实现其高精度,Skyfield需要计算非常高精度的地球方向,以使太阳在天空中的位置达到即使是射电天文学家也能达到的高精度。
但是如果你自己不需要那么高的精度,你可以切换到太阳的较低精度的天空坐标。在get_sun_position()中使用t之前,请尝试对其执行以下操作:
t._nutation_angles = iau2000b(t.tt)这将使用较低精度的地球章动估计(打印出更改前后的值,以查看差异有多大,并将其与您的应用程序可以承受的不精确度进行比较),但也有望运行得更快。
https://stackoverflow.com/questions/60974347
复制相似问题