2016-07-09 7 views
2

Я работаю над кросс-платформенным проектом Python. Это инструмент командной строки с автозавершением оболочки, поэтому скорость имеет значение.setuptools добавляет латентность запуска на 150 мс для всех скриптов

Путь setuptools создает консольный скрипт, налагающий минимум на 150 мс - иногда больше. Это просто неприемлемо для того инструмента, который я пишу, и не должен быть необходимым, учитывая, как мало он делает в основном случае.

Я стараюсь следовать лучшей практике для современного проекта Python, поэтому я использую setuptools для создания проекта. Пакет поддерживает окна, поэтому его способность генерировать двоичные обертки для точек входа очень важна.

Это происходит независимо от того, как установить пакет - pip install, pip install -e, pip install --egg, python setup.py install и т.д.

Там в github issue обсуждали эту проблему, но не обходной путь или решение до сих пор.

В другом месте я видел людей, возвращающихся к distutils из-за этого, но это не вариант для моего проекта.

Единственное обходное решение, которое я могу придумать, - это каким-то образом расширить или настроить то, что делает setuptools, когда он устанавливает проект, чтобы бинарная прокладка не использовала pkg_resources.

Что я могу сделать взамен этой довольно радикальной и неконструктивной меры?


Моего setup.py является основным - примерно следующим образом:

import pip.req 
import setuptools 

def install_reqs(): 
    reqs = pip.req.parse_requirements('requirements.txt', session=False) 
    reqs = [str(ir.req) for ir in reqs] 
    return reqs 

setuptools.setup(
    name='myproj', 
    version='v1.0.0-dev', 
    packages=setuptools.find_packages(exclude=('tests')), 
    install_requires=install_reqs(), 
    include_package_data=True, 
    entry_points={ 
     'console_scripts': [ 
      'myproj = myproj.cli.myproj:main', 
     ] 
    }, 
) 

Прокладка, что Setuptools генерирует для точки входа выглядит следующим образом:

!$myhome/.venv/myproj/bin/python 
# EASY-INSTALL-ENTRY-SCRIPT: 'myproj==1.0.0.dev0','console_scripts','myproj' 
__requires__ = 'myproj==1.0.0.dev0' 
import sys 
from pkg_resources import load_entry_point 

if __name__ == '__main__': 
    sys.exit(
     load_entry_point('myproj==1.0.0.dev0', 'console_scripts', 'myproj')() 
    ) 

Вот некоторые cProfile статистика с использованием Setuptools -генерированный сценарий консоли:

ncalls tottime percall cumtime percall filename:lineno(function) 
121/1 0.015 0.000 0.278 0.278 {built-in method builtins.exec} 
    1 0.000 0.000 0.278 0.278 myproj:3(<module>) 
125/3 0.001 0.000 0.221 0.074 <frozen importlib._bootstrap>:966(_find_and_load) 
125/3 0.001 0.000 0.221 0.074 <frozen importlib._bootstrap>:939(_find_and_load_unlocked) 
125/5 0.001 0.000 0.219 0.044 <frozen importlib._bootstrap>:659(_load_unlocked) 
99/5 0.001 0.000 0.219 0.044 <frozen importlib._bootstrap_external>:656(exec_module) 
152/4 0.000 0.000 0.218 0.054 <frozen importlib._bootstrap>:214(_call_with_frames_removed) 
    2 0.000 0.000 0.204 0.102 __init__.py:15(<module>) 
32/15 0.000 0.000 0.135 0.009 {built-in method builtins.__import__} 
    1 0.000 0.000 0.088 0.088 __init__.py:540(load_entry_point) 
    1 0.000 0.000 0.085 0.085 __init__.py:2564(load_entry_point) 
    1 0.000 0.000 0.083 0.083 __init__.py:2216(load) 

И здесь в качестве пользовательского сценария без Setuptools шайбы:

ncalls tottime percall cumtime percall filename:lineno(function) 
58/1 0.006 0.000 0.053 0.053 {built-in method builtins.exec} 
    1 0.000 0.000 0.053 0.053 test.py:1(<module>) 
53/3 0.000 0.000 0.052 0.017 <frozen importlib._bootstrap>:966(_find_and_load) 
53/3 0.000 0.000 0.052 0.017 <frozen importlib._bootstrap>:939(_find_and_load_unlocked) 
53/5 0.000 0.000 0.051 0.010 <frozen importlib._bootstrap>:659(_load_unlocked) 
65/4 0.000 0.000 0.051 0.013 <frozen importlib._bootstrap>:214(_call_with_frames_removed) 
45/5 0.000 0.000 0.051 0.010 <frozen importlib._bootstrap_external>:656(exec_module) 

Обычай сценария - test.py - очень просто:

from myproj.cli.myproj import main 

main() 
+0

Итак, напишите собственный сценарий. –

+0

Как мне его развернуть? Когда setuptools развертывает что-то из 'console_scripts' или' scripts', он генерирует прокладку, которая использует 'load_entry_point()', что происходит медленно. – Cera

ответ

0

Я видел этот вопрос тоже, если Я устанавливаю проект из источника, используя 'pip install.'. Однако, если я сначала создаю файл двоичного диска, а затем установите колесо, созданная прокладка не будет использовать pkg_resources и работает быстрее. Я проверил это с проектом cookiecutter:

https://github.com/audreyr/cookiecutter

Если я клонировать этот проект, а затем установить его, используя оригинальный метод «пункт установить.», Сгенерированный исполняемый скрипт содержит импорт из pkg_resources (и медленно):

#!/usr/local/opt/python3/bin/python3.5 
# EASY-INSTALL-ENTRY-SCRIPT: 'cookiecutter==1.5.1','console_scripts','cookiecutter' 
__requires__ = 'cookiecutter==1.5.1' 
import re 
import sys 
from pkg_resources import load_entry_point 

if __name__ == '__main__': 
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) 
    sys.exit(
     load_entry_point('cookiecutter==1.5.1', 'console_scripts', 'cookiecutter')() 
    ) 

Однако, если я делаю следующие две команды:

python setup.py bdist_wheel 
pip install dist/cookiecutter-1.5.1-py2.py3-none-any.whl 

генерируемый прокладка не содержит pkg_resources (и быстрее):

#!/usr/local/opt/python3/bin/python3.5 

# -*- coding: utf-8 -*- 
import re 
import sys 

from cookiecutter.__main__ import main 

if __name__ == '__main__': 
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) 
    sys.exit(main()) 

И когда я попробовал последний метод в Windows, он все еще создавал .exe-прокладку.

 Смежные вопросы

  • Нет связанных вопросов^_^