Как избежать повторного импорта модулей и переопределения большого объекта при каждом запуске скрипта

#python #python-2.7 #optimization #import #load

#python #python-2.7 #оптимизация #импорт #загрузить

Вопрос:

На это должен быть ответ, но я не могу его найти. Я использую довольно большой модуль 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... занимает около 30 секунд при 100% загрузке процессора. (Я считаю, что это связано с анализом большого XML-файла ascii.) Если бы я печатал в интерактивном режиме, я мог бы сохранить импортированный модуль и определить потенциал, но при запуске скрипта это выполняется снова при каждом запуске.

Могу ли я сохранить модуль и потенциальный объект в памяти / на диске между запусками? Может быть, сохранить процесс python на холостом ходу и сохранить эти вещи в памяти? Или запустите эти строки в интерпретаторе и каким-то образом вызовите остальную часть скрипта оттуда?

Любой подход подходит, но некоторая помощь будет оценена!

Комментарии:

1. Как часто вы вызываете скрипт? Если у вас достаточно оперативной памяти, ваша ОС будет кэшировать файлы модулей, используемые во import время . Если вы хотите сохранить pot , просто запишите его в файл, например, используя pickle .

Ответ №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)
  

Для этого существуют различные способы оптимизации, например, проверка того, старше ли ваш файл pickle, чем файл, генерирующий его значение.

Комментарии:

1. Я собираюсь попробовать wthis с вашим кодом, но на самом деле я только что попробовал с cPickle, и у меня это не сработало. Но что вы имеете в виду под необработанными файлами? Я думаю, что сохранение его в виде двоичного файла помогло бы, но как?

2. Что вы подразумеваете под «не заставило его работать»? Это часть стандартной библиотеки py2.7. Необработанные файлы — это просто файлы, в которые вы записываете простые строки без какой-либо библиотеки сверху. Например, if pot — это число с плавающей точкой, вы могли бы сделать store.write(str(pot)) и float(store.readline().strip()) .

3. Я не был хорошо сформулирован. cPickle не выдал ошибку ни при сбросе, ни при загрузке, но при попытке запустить загруженный потенциал я получил ошибку. И, глядя на файл, это было несколько байтов, а не размер реального объекта.

4. Какую ошибку вы получили? Какой объект вы храните?

5. Я не смог заставить ваш точный код работать, вместо этого я использовал полные выражения, начинающиеся с 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 только один раз, но тело столько, сколько необходимо:

 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"
  

Таким образом, это означает, что терминал занят, и скрипт затронут, но он работает.