Проблемы при замене модуля расширения Python во время выполнения скрипта Python - PullRequest
3 голосов
/ 11 июня 2010

Я пытаюсь решить следующую проблему: скажем, у меня есть скрипт Python (назовем его Test.py), который использует модуль расширения C ++ (сделанный через SWIG, давайте назовем модуль «Пример»).У меня есть Test.py, Example.py и _Example.so в одном каталоге.

Теперь, в середине работы Test.py, я хочу внести изменения в мой модуль Example, перекомпилировать (которыйперезапишет существующий .so) и с помощью команды изящно остановит Test.py, который все еще использует старую версию модуля (у Test.py есть некоторая очистка, которая использует некоторые вещи, определенные в модуле Example), затем запустите его снова, используя новую версию модуля.Изящная остановка Test.py и THEN перекомпиляция модуля в моем случае не вариант.

Проблема в том, что как только _Example.so перезаписывается и Test.py пытается получить доступ ко всему, что определено в модуле Example (в то время как изящно останавливаясь), я получаю ошибку сегментации.Одним из решений этой проблемы является явное присвоение имени модулю Example путем добавления номера версии в конце, но мне было интересно, есть ли лучшее решение (я не хочу импортировать Example_1_0)?

Ответы [ 2 ]

2 голосов
/ 11 июня 2010

При запуске Test.py вы можете скопировать файлы Example. * Во временную папку, уникальную для этого экземпляра (посмотрите на tempfile.mkdtemp , она может создавать безопасные уникальные папки), добавьте это к sys.path и затем импортируйте Example; и при завершении работы Test.py удалите эту папку ( shutils.rmtree ) на этапе очистки.

Это будет означать, что каждый экземпляр Test.py будет запускаться в своей собственной копии модуля Example, не мешая другим, и обновляться до новой только после повторного запуска.

Для этого вам понадобится, чтобы файлы Example. * Не находились в той же папке, что и Test.py, иначе импорт получит их в первую очередь. Просто храните их в подпапке.

0 голосов
/ 11 июня 2010

Вы можете скомпилировать временное имя (Example_1_0), но как только Test.py будет остановлен, переименуйте его в _Example.so и , затем перезапустите Test.py.


Edit:

Поскольку вы запускаете несколько экземпляров, вы можете рассмотреть возможность использования какого-либо типа stack / generator / symlink threading, чтобы связать все это вместе, чтобы сделать свою собственную "сборку мусора" на _Example.so:

Вы можете запустить основной сценарий тестера, запустив сценарии Test.py с подпроцессом. Каждый Test.py может принимать _ExampleXXX.so в качестве аргумента командной строки. Затем вы сохраняете счетчик ссылок для каждого .so-файла - когда значение refcount падает до нуля, эта версия модуля исключается и процесс запускается с самой новой версией _Example.so.

Это может быть немного сложно, но вы можете просто использовать

while True:
    #Do stuff
    for p in myprocesses:
        retcode = p.poll() # Set to [None][1] if the process hasn't finished
        # Do something with the return code

или подобная логика.

...