我有一个回测试引擎,我试图使用dask并行化。我可以独立地处理每周的数据,所以我认为我可以通过启动一个工作人员来轻松地进行并行化,该工作人员将创建一个完整的backtest引擎实例并在一周的数据上运行它。
以下是我根据Dask Futures docs尝试的大纲代码。
from dask.distributed import Client
from backtest_engine import *
def run_backtest(start_date, end_date):
engine = backtest_engine()
engine.price_spread = 2
engine.emulate_ticks = True
engine.run_walk_forward(start_date, end_date, 'my_market', my_strategy_class)
return True
if __name__ == "__main__":
client = Client()
a = client.submit(run_backtest, datetime(2017,9,3), datetime(2017,9,9))
b = client.submit(run_backtest, datetime(2017,9,10), datetime(2017,9,17))
使用以下代码调用client.submit()
时代码失败:
_pickle.PicklingError: Could not pickle object as excessively deep recursion required.
代码是否有问题,或者我的方法在某种程度上存在根本性的缺陷,或者我在工作人员的调用中是否存在限制?
伊恩
对于后台:run_walk_forward()
将HD5文件加载到Pandas数据帧中,遍历数据帧以生成结果,然后将结果写入磁盘。
答案 0 :(得分:1)
Dask使用cloudpickle进行功能序列化。我建议您尝试使用cloudpickle.loads(cloudpickle.dumps(obj))
函数和client.submit
的每个参数。
例如,某些依赖于您的函数(如backtest_engine
)可能依赖于一个不易序列化并在机器之间发送的锁定或打开文件。
答案 1 :(得分:0)
按照上面的MRocklin的建议,我逐个元素地运行了我的类,这里是导致上述异常的问题。
<强> 1。具有内在功能的类
感谢Emlyn O'Regan的blogpost让我意识到我的代码执行了以下操作并且无法进行腌制:
class A:
def __init__(self, parent):
self.parent = parent
def do_something():
# access self.parent
class B:
def my_func():
a = A(self)
a.do_something()
通过重写代码以将属性作为参数传递给适当的方法来修复。
<强> 2。类引用的全局变量
这只是匆匆编写的代码,我在类定义之外放置了一些常量变量(在启动时设置一次参数),然后从需要进行pickle的类中引用。
通过将变量移动到类定义中来解决。
第3。主模块中定义的类
我从主模块中的基类继承,以创建具有重写行为的新类。
>新类位于主名称空间中,因此无法进行腌制。解决方案只是将继承类的定义移动到一个单独的文件中,因此它位于除 main 之外的命名空间中。即代替:
my_script.py
class A:
# define stuff
if __name__ == "__main__":
# do stuff which will instantiate A
创建两个文件:
class_a.py
class A:
#define stuff
main.py
from class_a import A
if __name__ == "__main__":
# do stuff which at some point will instantiate A
伊恩