2016-03-17 30 views
4

我一直有使用Python的setuptools的一個奇怪的150ms的啓動點球,我已經構建了最小的測試案例和問題仍然存在有150ms的啓動處罰:對於這個最小奇怪〜使用python setuptools的

我的項目佈局案例:

- setup.py 
- setuptest 
- - __init__.py 
- - __main__.py 

的setup.py文件包含:

from setuptools import setup 

setup(
    name   = 'setuptest', 
    version  = '0.1', 
    packages  = ['setuptest'], 

    entry_points = { 
     'console_scripts' : ['setuptest = setuptest.__main__:main'] 
     } , 
    ) 

的__main__.py文件包含簡單:

#!/usr/bin/env python2 

def main(): 
    print "hai" 

if __name__ == '__main__': 
    main() 

這樣做的項目根目錄中:

—— — time python2 setuptest 
hai 

real 0m0.021s 
user 0m0.017s 
sys  0m0.004s 

給了我21 ms總執行腳本,但是,運行sudo python2 setup.py install和做後:

—— — time setuptest 
hai 

real 0m0.158s 
user 0m0.144s 
sys  0m0.012s 
—— — 

給我158ms。這個+ 150s的啓動延遲時間是一致的,發生在整個板上時,使用setuptools但沒有發生與我通過軟件包管理器安裝的東西或手動安裝其他人的項目,這讓我覺得我明顯在做一些事情錯。

+0

當您將'setup.py'內的'setup'調用包裝到'if __name__'中時,時間會發生變化嗎? –

+0

@SergeiLebedev,不,這似乎沒有改變任何東西,仍然約160-170毫秒爲一個簡單的hello世界計劃。 – Zorf

+0

對不起,我誤解了你的問題,雖然它是'setup.py'有延遲問題。 –

回答

-1

好吧,我找到了讓我感到困惑的答案,但它顯示了爲什麼別人更快。事實證明,即使setuptools被推薦爲更新更好,但由於某種原因,它也會增加性能惡化,至少在我的系統上,distutils不會。

這並快去使用distutils

編輯的示例中所有的軟件包:

from distutils.core import setup 

setup(
    name   = 'disttest', 
    version  = '0.1', 
    packages  = ['disttest'], 

    scripts  = ['bin/disttest'] 
    ) 

哪裏bin/disttest是項目的根充當周圍的真實程序解決了一個簡單的包裝中的可執行文件這個問題完全。從distutils.core而不是setuptools導入似乎是它的關鍵。可悲的是distuitls沒有方便的入口點機制。

2

好,當您使用的setuptools安裝一個軟件,它會產生一個bin目錄中的可執行腳本,它看起來像:

import sys 
from pkg_resources import load_entry_point 

if __name__ == '__main__': 
    sys.exit(
     load_entry_point('<PACKAGE_NAME>', 'console_scripts', '<ENTRY_POINT>')() 
    ) 

因爲load_entry_point()將通過在sys.path的更多地區所有軟件包解決和你已經安裝的軟件包,建立列表所用的時間越長,然後查找它。

有關詳細信息,我們需要看看setuptools的load_entry_point()實現:

setuptools.py:load_entry_point()

def load_entry_point(dist, group, name): 
    """Return `name` entry point of `group` for `dist` or raise ImportError""" 
    return get_distribution(dist).load_entry_point(group, name) 

'setuptools.py:get_distribution()'

def get_distribution(dist): 
    """Return a current distribution object for a Requirement or string""" 
    if isinstance(dist,basestring): dist = Requirement.parse(dist) 
    if isinstance(dist,Requirement): dist = get_provider(dist) 
    if not isinstance(dist,Distribution): 
     raise TypeError("Expected string, Requirement, or Distribution", dist) 
    return dist 

setuptools.py:Distribution.load_entry_point()

def load_entry_point(self, group, name): 
    """Return the `name` entry point of `group` or raise ImportError""" 
    ep = self.get_entry_info(group,name) 
    if ep is None: 
     raise ImportError("Entry point %r not found" % ((group,name),)) 
    return ep.load() 

setuptools.py:Distribution.get_entry_info()

def get_entry_info(self, group, name): 
    """Return the EntryPoint object for `group`+`name`, or ``None``""" 
    return self.get_entry_map(group).get(name) 

,我會留下它那裏,你可以跟進到那裏得到昂貴。我猜想在Distribution內完成映射的方法(如_dep_map屬性)在執行時可能非常昂貴。

+0

是的,但這並不能解釋爲什麼我所有的嘗試都花費150毫秒,而我從其他來源安裝的東西,通過軟件包管理器或其他方式,像他一樣進入20ms – Zorf

+0

我不確定你有多不同,重新進行兩個呼叫。但是,如果我嚴格閱讀你寫的內容,可能是因爲軟件包在當前目錄中,並且首先在'sys.path'中,它通過較少的目錄和模塊來找到它。您可能想要嘗試更改已安裝的可執行文件中的sys.path,以指向模塊的源代碼來檢查該假設。 – zmo

0

看來,如果您使用'python setup.py install'或'pip install'從源代碼安裝項目。 (創建一個.egg文件)生成的可執行腳本使用pkg_resources,這很慢。

但是,如果您先構建一個二進制輪盤文件(.whl),然後再安裝輪盤,則生成的可執行文件腳本不會從pkg_resources導入並且速度更快。以任意項目爲例,這裏是使用兩種不同方法安裝cookiecutter項目的結果。

https://github.com/audreyr/cookiecutter

如果這個項目是從使用「巨蟒的setup.py安裝」源代碼安裝,生成的可執行腳本包含通過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')() 
    ) 

然而,如果wheel文件是用以下兩條命令構建和安裝的:

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

鏈接是不夠的,請在您的答案中包含內容 – Alexan