加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – setuptools为所有脚本增加了150ms的启动延迟

发布时间:2020-12-20 13:13:05 所属栏目:Python 来源:网络整理
导读:我正在开发一个跨平台的 Python项目.它是一个带有shell自动完成功能的命令行工具,所以速度很重要. setuptools生成控制台脚本的方式是开销至少150ms – 有时更多.这对于我正在编写的工具来说是完全不可接受的,并且鉴于它在基本情况下的作用很小,因此不应该是
我正在开发一个跨平台的 Python项目.它是一个带有shell自动完成功能的命令行工具,所以速度很重要.

setuptools生成控制台脚本的方式是开销至少150ms – 有时更多.这对于我正在编写的工具来说是完全不可接受的,并且鉴于它在基本情况下的作用很小,因此不应该是必要的.

我正在尝试遵循现代Python项目的最佳实践,所以我使用setuptools来构建项目.该软件包支持windows,因此它为入口点生成二进制包装器的能力至关重要.

无论我如何安装软件包,都会发生这种情况 – 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','myproj')()
    )

以下是使用setuptools生成的控制台脚本的一些cProfile统计信息:

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()

解决方法

如果我使用’pip install’从源代码安装项目,我也看到了这个问题.但是,如果我首先构建二进制轮文件然后安装轮,则生成的垫片似乎不使用pkg_resources并且速度更快.我用cookiecutter项目测试了这个:

https://github.com/audreyr/cookiecutter

如果我克隆这个项目,然后使用原始方法’pip install.’进行安装,生成的可执行脚本包含从pkg_resources导入的(并且很慢):

#!/usr/local/opt/python3/bin/python3.5
# EASY-INSTALL-ENTRY-SCRIPT: 'cookiecutter==1.5.1','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','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填充程序.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读