У меня есть интерпретатор Python, встроенный в приложение. Приложение долго запускается, и у меня нет возможности перезапустить интерпретатор без перезапуска всего приложения. Что я хотел бы сделать, так это по существу сохранить состояние интерпретатора и легко вернуться в это состояние.
Я начал с сохранения имен всех модулей в sys.modules, с которых запускался интерпретатор python, а затем удаления всех новых модулей из sys.modules по запросу. Похоже, что это подготовило интерпретатор к повторному импорту тех же модулей, даже если он уже импортировал их раньше. Однако это работает не во всех ситуациях, например при использовании одноэлементных классов, статических методов и т. д.
Я бы предпочел не встраивать другой интерпретатор в этот интерпретатор, если этого можно избежать, поскольку будет потеряна простота использования API приложений (а также небольшое снижение скорости, как я полагаю).
Итак, кто-нибудь знает, как я мог бы сохранить состояние интерпретатора, а затем вернуться к нему, чтобы он мог справиться со всеми ситуациями?
Спасибо,
Дэн






Одним из очень хакерских и подверженных ошибкам подходов может быть модуль c, который просто копирует память в файл, чтобы его можно было загрузить обратно в следующий раз. Но поскольку я не могу представить, что это всегда будет работать должным образом, может ли травление быть альтернативой?
Если вы можете сделать все свои модули доступными для маринования, тогда вы сможете собрать все в globals (), чтобы его можно было перезагрузить снова.
Если вы заранее знаете, какие модули, классы, функции, переменные и т. д. Используются, вы можете записать их на диск и перезагрузить. Я не уверен, что лучший способ решить эту проблему, если ваша среда содержит много неизвестных. Хотя, возможно, хватит мариновать глобалов и локальных.
Попробуйте этот код из рецептов ActiveState: http://code.activestate.com/recipes/572213/
Он расширяет pickle, поэтому он поддерживает травление всего, что определено в консоли оболочки. Теоретически вы должны просто получить модуль основной в соответствии с их документацией:
import savestate, pickle, __main__
pickle.dump(__main__, open('savestate.pickle', 'wb'), 2)
Не работает для Python 3 в основном из-за изменений модуля pickle, например. pickle.Pickler.dispatch - это нечто иное, и pickle.Pickler.dispatch_table[...] выдаст ошибку при назначении встроенной функции и тому подобное. К сожалению, пока не нашел решения для Py3. :(
Я бы посоветовал устранить первопричину проблемы.
"The application takes a long time to start up and I have no ability to restart the interpreter without restarting the whole application"
Я сомневаюсь, что это на самом деле 100% правда. Если заявка в целом является результатом акта Конгресса, хорошо, ее нельзя изменить. Но если все приложение было написано реальными людьми, то поиск и перемещение кода для перезапуска интерпретатора Python должны быть возможны. Это дешевле, проще и надежнее, чем что-нибудь, иначе вы могли бы решить проблему.
Не в этом случае - приложение является основным программным обеспечением, выпускаемым только один раз в год. Пока эта функция не будет представлена, взлом - единственное доступное решение для ускорения разработки.
Я бы хотел, чтобы мое время так дорого стоило! Это то, что мне придется реализовать за час или два, чтобы попытаться облегчить себе жизнь. Если не получится, продолжим пользоваться существующей системой ...
storing the names of all modules in sys.modules that the python interpreter started with and then deleting all new modules from sys.modules when requested. This appears to make the interpreter prepared to re-import the same modules even though it has already imported them before.
Подход с принудительной перезагрузкой модуля может работать в некоторых обстоятельствах, но это немного сложно. В итоге:
Вам необходимо убедиться, что все модули, зависящие друг от друга, перезагружены одновременно. Таким образом, любой модуль 'x', который выполняет 'import y' или 'from y import ...', должен быть удален из sys.modules одновременно с модулем 'y'.
Этот процесс потребуется защитить блокировкой, если ваше приложение или любой другой активный модуль использует потоки.
Любой модуль, который оставляет хуки, указывающие на себя в других модулях, не может быть повторно загружен, поскольку ссылки на старый модуль останутся в незагруженном / выгружаемом коде. Сюда входят такие вещи, как перехватчики исключений, сигналы, фильтры предупреждений, кодировки, обезьяньи патчи и так далее. Если вы начнете беспечно перезагружать модули, содержащие чужой код, вы можете быть удивлены, как часто они делают подобные вещи, что может привести к незаметным и любопытным ошибкам.
Итак, чтобы заставить его работать, вам необходимо иметь четко определенные границы между взаимозависимыми модулями - «был ли он импортирован при первоначальном запуске», вероятно, недостаточно - и чтобы убедиться, что они хорошо инкапсулированы без неожиданных зависимостей, таких как обезьяна-патч.
Это может быть основано на папке, поэтому, например, что-либо в / home / me / myapp / lib может быть перезагружено как единое целое, оставив другие модули в покое, особенно содержимое stdlib, например. /usr/lib/python2.x/, который, как правило, ненадежно перезагружать. У меня есть код для этого в еще не выпущенной оболочке перезагрузки веб-приложений, если вам нужно.
Ну наконец то:
Это неприятная деталь реализации, которая может изменить и сломать ваше приложение в какой-то будущей версии Python, но это цена за игру с sys.modules неподдерживаемыми способами.
Я думаю, что проблема такого подхода в поддержании состояния. Модуль имеет собственное пространство имен (как и функции и классы внутри него), поэтому любой вызов функции может изменить это состояние. Даже порядок импорта может иметь значение, если модуль запускает код в своем глобальном пространстве имен (при импорте).
Это выглядит многообещающе, спасибо, я рассмотрю это немного подробнее.