Python, setuptools, wheel, entry_points, оболочки.exe для Windows и многопроцессорность
TL;DR; - Оболочка сценария setuptools/distutils.exe entry_points не запускает бесконечную рекурсию многопроцессорной обработки Windows. Оболочка колеса.exe entry_points сделать. Как я могу получить предыдущее поведение?
Многие из нас, вероятно, столкнулись с проблемой с многопроцессорным модулем Python 2.X и Windows с бесконечной рекурсией при непосредственном вызове скрипта модуля.
Когда я создал точку входа для своей библиотеки, которая привела к функции с многопроцессорной обработкой, сценарий точки входа и обертываемый файл.exe были запущены в Windows, когда я установил их с помощью setuptools, с возможностью непосредственного запуска функции, которая вызвала многопроцессорную обработку. и обрабатывать объекты. Это было здорово, потому что моя библиотека зависела от многопроцессорности, чтобы ускорить постыдную параллельную программу.
Все работало хорошо, пока я не попытался использовать bdist_wheel для совместного использования библиотеки. Хотя в процессе сборки ранее были добавлены оболочка.exe и сценарии, оболочка.exe не была такой же.
Мои навыки форматирования двоичных файлов далеки от хороших, но я знал, что был какой-то перевод сжатого zip-файла в исполняемый файл, который я видел, поэтому я пошел и сделал единственную логическую вещь и разархивировал файл.exe. Я использовал 7zip, так как даже в моей оболочке mingw bash не было zip/unzip. Оболочка.exe, установленная из файла Wheel, распаковывается в каталог, содержащий простой основной скрипт.py,
# -*- coding: utf-8 -*-
import re
import sys
from example_multiprocessing.runner import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
Это был просто скрипт Python, запущенный из zip-файла. Не удивительно, что он взорвался.
Я переустановил с помощью setup.py, добавив обратно старую оболочку.exe, и попытался разархивировать это. И вот, это полный файл исполняемого файла с разделами.data,.pdata,.rdata и.text, которые 7zip извлекли в свои файлы. Два часа спустя, я копался в исходном коде distutils и setuptools, чтобы выяснить, что там происходит, и обнаружил, что.exe, который я вижу, сделан путем заливки некоторого специфичного для точки входа кода python в предварительно созданный exe-файл запуска для Windows. Отлично. Я знаю больше, чем раньше. Но если разница заключалась в обертке.exe, почему работает -script.py entry_point?
__requires__ = 'example-multiprocessing==1.0.2'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('example-multiprocessing==1.0.2', 'console_scripts', 'example-mp-run')()
)
Является load_entry_point
специальный? Это оболочка для EntryPoint.load(), которая используется для явного вызова __import__
:
# From [https://bitbucket.org/pypa/pkg_resources/src/33e56f318f5086158de8bb2827acb55db2dbc153/pkg_resources.py?at=default#cl-2258][1]
def load(self, require=True, env=None, installer=None):
if require: self.require(env, installer)
entry = __import__(self.module_name, globals(),globals(), ['__name__'])
for attr in self.attrs:
try:
entry = getattr(entry,attr)
except AttributeError:
raise ImportError("%r has no %r attribute" % (entry,attr))
return entry
globals()
выглядеть тупиком из документации __import__
, но ['__name__']
Похоже, это может быть полезно. Беда в том, что __import__
является встроенным, и он реализован на C. Я попытался прочитать зеркало, размещенное на GitHub, но на данный момент это не в моем вкусе, разделение на три или более взаимодействующих функций, которые я не могу отследить и поддерживать связь с из списка. Я также могу отвлекаться на __import__
так как следующий блок после того, как он пытается получить доступ к атрибуту модуля, хранящегося в entry
Я предполагаю, что сама функция точки входа.
Когда я запускаю следующий код:
getattr(__import__("example_multiprocessing.runner", globals(), globals(), ["__name__"]), "main")()
Я вижу основную функцию, в которой я ожидал запустить execute и вернуть без проблем.
Является __import__
действительно делает работу, в которой я нуждаюсь, __name__
скрипта к чему-то не включающему __main__
? Почему не работает, машина позади -m работает?