调用Client.Submit时来自Dask的PicklingError

时间:2017-11-07 05:26:48

标签: python multiprocessing dask

我有一个回测试引擎,我试图使用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数据帧中,遍历数据帧以生成结果,然后将结果写入磁盘。

2 个答案:

答案 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

伊恩