Python 3:猴子补丁代码不能通过多处理重新导入

Posted

技术标签:

【中文标题】Python 3:猴子补丁代码不能通过多处理重新导入【英文标题】:Python 3: Monkey-patched code not re-importable by multiprocessing 【发布时间】:2012-09-07 19:07:01 【问题描述】:

简介

当模块 A 的函数应该是可导入的时,我如何从模块 B 修补模块 A,以便我可以使用 multiprocessing 标准库包运行模块 A 的函数?

背景

一个客户请求了一个不适用于我们任何其他客户的修补程序,因此我创建了一个新分支并为他们编写了一个单独的模块,以便轻松合并来自主分支的更改。为了保持客户端与预修补程序行为的向后兼容性,我将修补程序实现为应用程序中的可配置设置。因此,我不想替换我的旧代码——只需在设置打开时对其进行修补。我是通过monkey patching 完成的。

代码结构

__main__ 模块读取配置文件。如果配置打开了修补程序的开关,__main__ 通过用hotfix 模块中定义的代码替换几个函数来修补我的engine 模块——本质上,被替换的函数是key function to a maximization function。 engine 模块稍后会加载一个 multiprocessing 工人池。

问题

一旦multiprocessing worker 启动,首先multiprocessing 执行re-imports* engine 模块并寻找__main__ 试图替换的关键功能(然后multiprocessing 交出控制我的代码并开始最大化算法)。由于engine 正在被一个全新的进程重新导入,并且新进程不会重新运行__main__(读取配置文件的位置),因为这会导致无限循环,它不知道重新运行猴子补丁engine.

问题

如何在我的代码中保持模块化(即,将修补程序代码保存在单独的模块中)并仍然利用 Python 的 multiprocessing 包?

* 请注意,我的代码必须在 Windows(为了我的客户端)和 Unix(为了我的理智......)上运行

【问题讨论】:

+1,格式很好的问题。但是multiprocessing 不会在子进程中重新导入__main__ 吗? @nneonneo,是的,但是重新运行 __main__.main() 会导致无限循环。 当然,当然。但是你不能有单独的read_configmain() 方法,并调用read_config 而不是main() 我如何让__main__ 确定它是作为multiprocessing 工作人员还是从命令行加载的? 看我的回答。我相信这应该为你做。 【参考方案1】:

这听起来像是猴子修补不起作用的地方。将相关功能提取到单独的模块并让引擎从那里导入它们更容易。也许您可以对从何处导入它们进行配置设置。

另一种模块化的方法是使用某种组件架构,例如ZCA。最后一个选项是我会选择的,但那是因为我已经习惯了,所以对我来说没有额外的学习。

【讨论】:

【参考方案2】:

要使其在具有fork() 的 UNIX/Linux 操作系统上运行,您无需执行任何特殊操作,因为新进程可以访问与父进程相同的(猴子补丁)类。

要使其在 Windows 上运行,请让您的 __main__ 模块在导入时读取配置(将 read_config/patch_engine 调用置于全局范围内),但在 if __name__ == '__main__' 中执行多处理(引擎执行)守卫。

然后,无论何时导入 __main__(从命令行或从 multiprocessing 重新导入),都会执行读取配置代码,但仅当从命令行(因为__main__ 在子进程中以不同的名称重新导入)。

【讨论】:

【参考方案3】:

听起来您将不得不修改 engine.py 以检查配置文件,并在需要时自行修补。

要同时在 unix 和 Windows 上工作,engine 可以保留一个全局 CONFIG_DONE 变量来决定是否需要再次检查配置文件。

【讨论】:

以上是关于Python 3:猴子补丁代码不能通过多处理重新导入的主要内容,如果未能解决你的问题,请参考以下文章

Python基础复习函数篇

ruby 可选的Jekyll猴子补丁使用终端通知器来指示Jekyll构建完成。放入_plugins / ext.rb

Python之猴子补丁

python的猴子补丁monkey patch

php中的猴子补丁

Python 中的鸭子类型和猴子补丁