静静地重启Python解释器

时间:2009-01-10 17:56:27

标签: python interpreter

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

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

如果可以避免,我宁愿不在此解释器中嵌入另一个解释器,因为能够使用应用程序API的容易性将会丢失(以及包括我想象的轻微速度命中)。

那么,有没有人知道我可以存储解释器的状态然后返回到这个以便它可以应对所有情况的方式?

谢谢,

5 个答案:

答案 0 :(得分:4)

尝试使用ActiveState食谱中的代码:http://code.activestate.com/recipes/572213/

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

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

答案 1 :(得分:1)

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

  

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

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

答案 2 :(得分:1)

  

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

模块重载强制方法可以在某些情况下工作,但它有点毛茸茸。总结:

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

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

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

因此,要使其工作,您需要在相互依赖的模块之间有明确定义的边界 - “它是在初始启动时导入的”可能不够好 - 并且确保它们很好地封装而没有意外的依赖,如猴子修补。

这可以基于文件夹,因此例如/ home / me / myapp / lib中的任何内容都可以作为一个单元重新加载,同时保留其他模块 - 尤其是stdlib的内容。 /usr/lib/python2.x/通常不能重新加载。如果你需要,我已经在一个尚未发布的webapp重新加载包装器中获得了这个代码。

最后:

  • 您需要了解一下sys.modules的内部结构,特别是它留下了一堆'None'值来表示失败的相对导入。如果您在删除其他模块值的同时不删除它们,则后续导入模块的尝试可能(有时)最终导入“无”,从而导致混淆错误。

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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