【问题标题】:How to avoid re-importing modules and re-defining large object every time a script runs如何避免每次脚本运行时重新导入模块和重新定义大对象
【发布时间】:2016-10-10 01:13:39
【问题描述】:

这一定有答案,但我找不到。我正在使用一个非常大的 python 模块,称为 quippy。有了这个模块,我们可以定义一个分子间势能在 ASE 中用作计算器,如下所示:

from quippy import *
from ase import atoms
pot=Potential("Potential  xml_label=gap_h2o_2b_ccsdt_3b_ccsdt",param_filename="gp.xml")
some_structure.set_calculator(pot)

这是脚本的开始。问题是import 大约需要 3 秒,pot=Potential... 在 100% cpu 负载下需要大约 30 秒。 (我相信这是由于解析了一个大的 ascii xml 文件。)如果我要交互输入,我可以保持导入模块并定义潜在的,但是在运行脚本时,它会在每次运行时再次完成。

我可以在运行之间将模块和潜在对象保存在内存/磁盘中吗?也许让python进程空闲并将这些东西保存在内存中?或者在解释器中运行这些行并以某种方式从那里调用脚本的其余部分?

任何方法都可以,但不胜感激!

【问题讨论】:

  • 您多久调用一次脚本?如果您有足够的 RAM,您的操作系统将缓存 import 期间使用的模块文件。如果要存储pot,只需将其写入文件,例如使用pickle

标签: python python-2.7 optimization import load


【解决方案1】:

您可以使用原始文件或pickle 等模块轻松存储数据。

import cPickle as pickle
from quippy import Potential
try:  # try previously calculated value
    with open('/tmp/pot_store.pkl') as store:
        pot = pickle.load(store)
except OSError:  # fall back to calculating it from scratch
    pot = quippy.Potential("Potential  xml_label=gap_h2o_2b_ccsdt_3b_ccsdt",param_filename="gp.xml")
    with open('/tmp/pot_store.pkl', 'w') as store:
        pot = pickle.dump(pot, store)

对此有各种优化,例如检查您的泡菜文件是否比生成它的值的文件旧。

【讨论】:

  • 我将尝试使用您的代码,但实际上我只是尝试使用 cPickle 并没有让它工作。但是你对原始文件是什么意思?我认为将其保存为二进制文件会很有效,但是如何?
  • “没有让它工作”是什么意思?它是 py2.7 标准库的一部分。原始文件只是您编写纯字符串的文件,顶部没有任何库。例如,如果pot 是一个浮点数,您可以使用store.write(str(pot))float(store.readline().strip())
  • 我没有很好地制定。 cPickle 没有给出错误,无论是在转储还是在加载时,但是在尝试运行加载的电位时,我得到了一个错误。看着文件,它只有几个字节,不接近真实对象的大小。
  • 你遇到了什么错误?你存储什么样的对象?
  • 我没有让您的确切代码工作,而是使用以with 开头的完整表达式来转储和加载pot。我转储,退出解释器,重新进入解释器并加载它(连同通常的导入)。然后>>> type(pot) 正确给出<class 'quippy.potential.Potential'> 但在第一行使用潜在的object.set_calculator(pot) 我得到Segmentation fault 并且没有更多信息。我怀疑这个对象不能腌制。
【解决方案2】:

我找到了一种解决方案,但我对替代方案很感兴趣。您可以将脚本分为两部分:

start.py:

from quippy import Potential
from ase import atoms
pot=Potential(...  etc...

body.py:

for i in range(max_int):
      print "doing things"
# etc...

然后进入python解释器,只运行一次start-script,但body尽可能多地运行:

me@laptop:~/dir$ python
>>> execfile('start.py')
>>> execfile('body.py')
>>> #(change code of "body.py" in editor)
>>> execfile('body.py') # again without reloading "start.py"

所以这意味着一个终端被占用并且脚本受到影响,但它可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-17
    • 2018-01-28
    • 2022-01-24
    • 2016-08-23
    • 2021-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多