我在应用程序中嵌入了一个 python 解释器。该应用程序需要很长时间才能启动,并且我无法在不重新启动整个应用程序的情况下重新启动解释器。我想做的是本质上保存解释器的状态并轻松返回到该状态。

我首先将 python 解释器启动时使用的所有模块的名称存储在 sys.modules 中,然后根据请求从 sys.modules 中删除所有新模块。这似乎使解释器准备重新导入相同的模块,即使它之前已经导入过它们。然而,这似乎并不适用于所有情况,例如使用单例类和静态方法等。

如果可以避免的话,我宁愿不在这个解释器中嵌入另一个解释器,因为将失去使用应用程序 API 的便利性(以及我想象的轻微的速度影响)。

那么,有谁知道我可以存储解释器状态然后返回到此状态以便它可以应对所有情况的方法吗?

谢谢,

有帮助吗?

解决方案

从ActiveState食谱中尝试此代码: http://code.activestate.com/recipes/572213 /

它扩展了pickle,因此它支持在shell控制台中定义的任何东西。从理论上讲,你应该能够根据他们的文档挑选模块:

import savestate, pickle, __main__
pickle.dump(__main__, open('savestate.pickle', 'wb'), 2)

其他提示

我建议解决根本原因问题。

  

“申请需要很长时间   启动,我没有能力   没有重启解释器   重新启动整个应用程序“

我怀疑这实际上是100%真实。如果整个申请是国会法案的结果,那么就不能改变。但如果整个应用程序是由真人编写的,那么找到并移动代码以重新启动Python解释器应该是可能的。它比任何更便宜,更简单,更可靠。否则你可能会解决这个问题。

将 python 解释器启动的所有模块的名称存储在 sys.modules 中,然后根据请求从 sys.modules 中删除所有新模块。这似乎使解释器准备重新导入相同的模块,即使它之前已经导入过它们。

模块重新加载强制方法可以在某些情况下工作,但有点麻烦。总之:

  • 您需要确保所有相互依赖的模块都立即重新加载。因此,任何执行“import y”或“from y import ...”的模块“x”必须与模块“y”同时从 sys.modules 中删除。

  • 如果您的应用程序或任何其他活动模块正在使用线程,则此过程将需要用锁进行保护。

  • 任何在其他模块中留下指向自身的钩子的模块都无法有效地重新加载,因为对旧模块的引用将保留在未重新加载/不可重新加载的代码中。这包括异常钩子、信号、警告过滤器、编码、猴子补丁等。如果您开始愉快地重新加载包含其他人代码的模块,您可能会惊讶于他们经常做这样的事情,这可能会导致微妙而奇怪的错误。

因此,为了让它工作,你需要在相互依赖的模块之间有明确的边界——“它是在初始启动时导入的”可能还不够好——并确保它们被很好地封装,没有意外的依赖关系,比如猴子修补。

这可以基于文件夹,因此例如 /home/me/myapp/lib 中的任何内容都可以作为一个单元重新加载,同时保留其他模块 - 特别是例如中的 stdlib 的内容。/usr/lib/python2.x/ 通常重新加载不可靠。如果您需要的话,我在尚未发布的 Web 应用程序重新加载包装器中提供了相关代码。

最后:

  • 您需要了解一些有关 sys.modules 内部结构的信息,特别是它留下了一堆“None”值来表示失败的相对导入。如果您在删除其他模块值时没有同时删除它们,则随后尝试导入模块可能(有时)最终会导入“None”,从而导致令人困惑的错误。

这是一个令人讨厌的实现细节,可能会在未来的某个 Python 版本中更改和破坏您的应用程序,但这就是以不受支持的方式使用 sys.modules 的代价。

一个非常容易出错且容易出错的方法可能是一个c模块,它只是将内存复制到一个文件中,以便下次可以加载回来。但是既然我无法想象这总能正常运作,那么酸洗会不会成为另类呢?

如果你能够使你的所有模块都可以腌制,那么你应该能够在globals()中腌制所有模块,这样它就可以重新加载了。

如果您事先知道正在使用的模块,类,函数,变量等,您可以将它们腌制到磁盘并重新加载。如果您的环境包含许多未知数,我不确定解决问题的最佳方法。虽然,它可能足以腌制全球和当地人。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top