У меня есть модуль python, который использует огромную глобальную переменную словаря, в настоящее время я помещаю вычислительный код в верхнюю часть, каждый первый импорт или перезагрузка модуля занимает более одной минуты, что совершенно неприемлемо. Как я могу где-нибудь сохранить результат вычислений, чтобы при следующем импорте / перезагрузке не приходилось его вычислять? Я попробовал cPickle, но загрузка словарной переменной из файла (1,3 МБ) занимает примерно столько же времени, сколько и вычисление.
Чтобы предоставить больше информации о моей проблеме,
FD = FreqDist(word for word in brown.words()) # this line of code takes 1 min
Я согласен со следующими ответами, но вам действительно следует предоставить более подробную информацию о типе данных, о том, как они создаются и для чего они предназначены (цель и процесс), поскольку правильное решение во многом зависит от этого.
Я добавил строку кода выше.






Я предполагаю, что вы вставили буквальный dict в источник, и это занимает минуту? Я не знаю, как это обойти, но вы, вероятно, могли бы избежать создания этого dict на импорт ... Вы могли бы лениво создать его при первом фактическом использовании.
FD = FreqDist (слово в слово в brown.words ()) # эта строка кода занимает одну минуту
Если FD каждый раз одно и то же, вставьте результаты «print FD» прямо в исходный файл и пропустите этап вычислений.
FD - это огромный экземпляр стороннего класса, который нельзя записать буквально.
Вы можете использовать полка для хранения ваших данных на диске вместо загрузки всех данных в память. Таким образом, время запуска будет очень быстрым, но компромисс - более медленное время доступа.
Shelve также будет обрабатывать значения dict, но будет выполнять (un) pickle не при запуске для всех элементов, а только во время доступа к каждому элементу.
Рассчитайте глобальную переменную при первом использовании.
class Proxy:
@property
def global_name(self):
# calculate your global var here, enable cache if needed
...
_proxy_object = Proxy()
GLOBAL_NAME = _proxy_object.global_name
Или, что еще лучше, доступ к необходимым данным через специальный объект данных.
class Data:
GLOBAL_NAME = property(...)
data = Data()
Пример:
from some_module import data
print(data.GLOBAL_NAME)
См. Настройки Django.
Вы можете попробовать использовать модуль маршал вместо модуля c? Pickle; это могло быть быстрее. Этот модуль используется python для хранения значений в двоичном формате. Обратите особое внимание на следующий абзац, чтобы узнать, подходит ли маршал вашим потребностям:
Not all Python object types are supported; in general, only objects whose value is independent from a particular invocation of Python can be written and read by this module. The following types are supported: None, integers, long integers, floating point numbers, strings, Unicode objects, tuples, lists, sets, dictionaries, and code objects, where it should be understood that tuples, lists and dictionaries are only supported as long as the values contained therein are themselves supported; and recursive lists and dictionaries should not be written (they will cause infinite loops).
На всякий случай перед демаршализацией dict убедитесь, что версия Python, которая демаршалирует dict, такая же, как и та, которая выполняла маршал, поскольку нет никаких гарантий обратной совместимости.
Расширяя идею отложенного вычисления, почему бы не превратить dict в класс, который предоставляет (и кэширует) элементы по мере необходимости?
Вы также можете использовать psyco для ускорения общего выполнения ...
Вы также можете проверить pyrex / cython.
Психо, кажется, работает только на 32-битных системах
ИЛИ ЖЕ вы могли бы просто использовать базу данных для хранения значений? Обратите внимание на SQLObject, который позволяет очень легко сохранять данные в базе данных.
Чтобы уточнить: код в теле модуля - это нет, который выполняется каждый раз, когда модуль импортируется - он запускается только один раз, после чего будущий импорт находит уже созданный модуль, а не воссоздает его. Взгляните на sys.modules, чтобы увидеть список кэшированных модулей.
Однако, если ваша проблема - это время, необходимое для первого импорта после запуска программы, вам, вероятно, придется использовать какой-то другой метод, кроме python dict. Вероятно, лучше всего было бы использовать дисковую форму, например базу данных sqlite, один из модулей dbm.
Для минимального изменения вашего интерфейса лучшим вариантом может быть модуль полки - это обеспечивает довольно прозрачный интерфейс между модулями dbm, который заставляет их действовать как произвольный Python dict, позволяя сохранять любое выбираемое значение. Вот пример:
# Create dict with a million items:
import shelve
d = shelve.open('path/to/my_persistant_dict')
d.update(('key%d' % x, x) for x in xrange(1000000))
d.close()
Затем используйте его в следующем процессе. Не должно быть большой задержки, так как поиск выполняется только для ключа, запрошенного в форме на диске, поэтому все не должно загружаться в память:
>>> d = shelve.open('path/to/my_persistant_dict')
>>> print d['key99999']
99999
Это немного медленнее, чем настоящий dict, и воля по-прежнему долго загружается, если вы делаете что-то, для чего требуются все ключи (например, пытаетесь распечатать его), но может решить вашу проблему.
Несколько вещей, которые помогут ускорить импорт:
С учетом сказанного, я согласен с тем, что вы не должны испытывать никаких задержек при импорте модулей после первого импорта. Вот еще пара общих мыслей:
С учетом сказанного, немного сложно дать вам какой-либо конкретный совет без небольшого дополнительного контекста. В частности, куда вы это импортируете? А какие вычисления?
Выделите вычислительно-интенсивную часть в отдельный модуль. Тогда, по крайней мере, при перезагрузке ждать не придется.
Попробуйте сбросить структуру данных по протоколу 2. Попробуйте выполнить команду cPickle.dump(FD, protocol=2). Из строки документации для cPickle.Pickler:
Protocol 0 is the only protocol that can be written to a file opened in text mode and read back successfully. When using a protocol higher than 0, make sure the file is opened in binary mode, both when pickling and unpickling.
Кажется, что наличие кода в отдельном модуле не очень помогает, при перезагрузке этого модуля код в отдельном модуле снова запускается.
Есть еще одно довольно очевидное решение этой проблемы. Когда код перезагружается, исходная область все еще доступна.
Итак ... выполнение чего-то подобного гарантирует, что этот код будет выполнен только один раз.
try:
FD
except NameError:
FD = FreqDist(word for word in brown.words())
shelve работает очень медленно с большими наборами данных. Я довольно успешно использовал Redis и написал вокруг него Оболочка FreqDist. Это очень быстро, и к нему можно обращаться одновременно.
Я прохожу через ту же проблему ... полки, базы данных и т. д. слишком медленны для этого типа проблем. Вам нужно будет принять удар один раз, вставить его в хранилище ключей / val inmemory, например Redis. Он просто будет жить там в памяти (предупреждаем, что он может использовать хороший объем памяти, поэтому вам может понадобиться специальный ящик). Вам никогда не придется перезагружать его, и вы просто будете искать в памяти ключи
r = Redis()
r.set(key, word)
word = r.get(key)
Не могли бы вы прояснить: нужна ли вам постоянство между вызовами разных интерпретаторов Python или вы спрашиваете о множественном импорте в одном экземпляре интерпретатора?