如何根据fork()复制状态重构Python代码

如何根据fork()复制状态重构Python代码,python,multiprocessing,fork,state,Python,Multiprocessing,Fork,State,我正在开发一个大型的ish-Python代码库,这个代码库已经存在了十多年了。所讨论的应用程序利用forking实现并行性 基本前提是,用户要求程序构建一个特定的目标,我们计算出目标的依赖图,然后从构建图中的拓扑分区计算出一些我们可以并行执行的任务。然后,我们分叉一些进程来并行执行这些任务(来自分区) 这一切都很有效。但是,我想重构它,使其不依赖于fork()。特别是,子进程中主进程的状态依赖性是一个问题 重构有几个激励因素: 我希望Linux和Linux之间的代码尽可能相似 和Windows(

我正在开发一个大型的ish-Python代码库,这个代码库已经存在了十多年了。所讨论的应用程序利用forking实现并行性

基本前提是,用户要求程序构建一个特定的目标,我们计算出目标的依赖图,然后从构建图中的拓扑分区计算出一些我们可以并行执行的任务。然后,我们分叉一些进程来并行执行这些任务(来自分区)

这一切都很有效。但是,我想重构它,使其不依赖于
fork()
。特别是,子进程中主进程的状态依赖性是一个问题

重构有几个激励因素:

  • 我希望Linux和Linux之间的代码尽可能相似 和Windows(目前在Windows上,我们执行非分叉构建, 因此没有平行性)
  • 叉子有点难看 我想做的其他重构(基本上,我希望有更多 建筑物的集中控制和监控)。而不是分叉, 我想介绍一下Python多处理模块(我已经介绍过了) 过去使用过,效果良好)
  • 问题在于,分叉进程(由主进程设置)当前使用的大量数据结构无法轻松序列化(也无法通过子进程推断它们的构造)。开放文件描述符就是这样一个例子,依赖对象标识(构建图)是另一个例子


    基本上,我在寻求如何从整体上最好地解决这个问题的建议。

    我提出以下范例

    Master是一个单独的进程,它执行所有依赖项解析、图形分区等操作,直至单个作业。因此,系统状态只有一个副本

    使用
    子进程
    多处理
    操作系统
    卸载这些叶作业

    卸载机制越简单,平台独立性越强:)

    叶子当然是异步的,因此您需要一个处理异步通知的框架——您可以使用
    gevent
    或一些实现
    未来
    的库。如果你是真正的铁杆,
    twisted
    。Python3.x还引入了可能有用的
    asyncio


    您还可以将资源/执行器池与特别通知一起使用,例如,我认为可以相对简单地使用递归函数或递归生成器来实现这些通知。

    @AlexShkop multiprocessing module最终是我想要结束的地方。然而,真正的问题是解决对使用分叉复制的状态的依赖性。请注意,在Linux上,多处理会产生带有fork(状态复制)的新进程,而在Windows上(没有fork)则不会。我不知道为什么必须重用指向文件描述符的指针。听起来是个坏主意。无论如何,您必须区分数据和助手、访问者等。FD不是数据。您可以将所有数据放在共享位置(例如sqlite?)。现在,您可以简单地在同一共享结构上运行独立的进程。这基本上就是当前代码所做的(主进程中的完全依赖关系解析,要构建的原子目标被发送到子进程)。问题是要构建的目标(由依赖项解析确定)是a)具有大量当前无法序列化的状态的复杂对象(包括文件描述符)和b)很难进入可以序列化的状态(由于我们的代码库的性质)。只要在这些“叶子”中不使用Python执行繁重的计算,也许可以将它们分解为一系列
    os.system
    subprocess.Popen
    调用?在这种情况下,您可以完全使用
    线程
    ,或者如果外部操作的总数太大,
    gevent
    。重点是将目标逻辑移到主流程中。我想我真正问题的答案是“如果你不能很好地描述一个构建任务而不进行分叉,那么代码需要重构”。没有一种神奇的方法能够以平台无关的方式提供类似于fork的功能。将此答案标记为已接受,因为它最接近“正确”。一点OT:流程中最接近
    fork
    的是
    cPickle.loads(cPickle.dumps(obj))
    。它甚至比
    copy.deepcopy()
    更好。但是,要使自定义类和资源可拾取/可查找,可能需要做很多工作。