Python解释器启动需要大约12秒,所有这些都花在`import pyexpat`上

问题描述 投票:4回答:1

我在我的Mac上使用了Homebrew安装的Python(运行OS X 10.13.1),最近,我注意到解释器需要很长时间才能启动。

在试图解决这个问题时,我用time做了一个简单的检查:

PIPER-ALPHA:~$ time bpython -c 'pass'

real    0m12.141s
user    0m1.662s
sys     0m10.073s

...揭示了问题的严重性:12秒!

然后我使用了gnomon--一个extremely handy npm module用于逐项列出CLI工具的时间 - 将问题告诉了令人讨厌的Python模块。我使用了这个命令:

PIPER-ALPHA:~$ PYTHONVERBOSE=1 bpython -c 'pass' 2>&1 | tee -a /tmp/bpython-startup-messages | gnomon

... gnomon输出显示详细的Python解释器输出发出的每一行所用的时间。它看起来像这样:

verbose Python interpreter startup output timed with gnomon

...我已经突出显示了执行时间近十二秒的输出 - 到目前为止最长,因为每一条其他线通常需要几纳秒,或者最多几微秒。

通常情况下,如果我遇到一个不稳定的Python扩展,我会自己重新编译它,或者从源代码调整它,以便在必要时正确地呈现它。但是在这种情况下,我正在处理一个c-extension模块,它是一个更大的Python标准库模块的一部分,所有这些模块都附带了Homebrew二进制包(在Homebrew中称为“瓶子”),包含这个版本的Python。

这是其他任何人都可以证明的问题吗?特别是,在类似情况下运行Python时,是否是其他人看到的问题?而且,最重要的是,我该如何解决它?我是否需要重建整个Python安装,使用Homebrew还是不使用Homebrew?

python performance homebrew python-c-api expat-parser
1个回答
2
投票

我已经想到了这一点 - 答案结果是同时发光和令人尴尬 - 我的解决方案可能会在遇到类似情况时帮助其他人。

简而言之:在加载Python解释器时,由于安装了过多的Python扩展模块,导致我经历了长时间〜12秒的停顿。这不是Python 2.7捆绑的xml.parsers.expat模块的问题,也不是它的C-API pyexpat扩展。

也就是说:我使用gnomon工具,它提供了指向这些模块的直接和直接的证据,最终误导了我在哪里找到有问题的代码。

在发布我的问题后,我做了一些额外的法医调查。通过改变我在调用命令行速度检查时传递给解释器的Python代码,我发现gnomon报告将显示相同的12秒以上的停止,但是在不同的import语句的发生率。此外,我发现一些命令变体(例如使用pythonpy CLT执行的变体)完全不受停止行为的困扰。

当我偶然偶然发现问题时,我能够找到导致问题表现的代码行 - 在运行我的测试时,无休止的长时间停止也不会令人讨厌,我最终控制了C-a的一些测试在中途停止。那些中止的测试运行以KeyboardInterrupt异常终止,并且随附的stacktrace输出显示了拖动事物的功能:

exculpatory stacktrace

... pkg_resources模块在导入时,遍历sys.path中命名的每个扩展目录,枚举每个扩展中的每个包,然后读入然后解析所有这些的所有相关元数据。使用pkg_resources的任何部分(它本身是必要的setuptools模块的一部分)会触发这个耗时的操作(至少在特定解释器调用的生命周期内缓存)。根据你的Python安装设置方式以及你如何调用你的解释器,你可能会或者可能不会最终做一些事情来触发pkg_resources的使用,但它在Python扩展包中的用途非常广泛,所以很有可能它会被某种东西触发。

actual function responsible for the actual loop that actually enumerates the packages_initialize_master_working_set() - 这是我在上面的截图中突出显示的那个。这就是我所有的KeyboardInterrupt堆栈跟踪所揭示的内容。从那里,很明显,令人沮丧的停顿是干酪店包装数量的急剧线性函数(升级我的笔记本电脑后我一直在鲁莽)。

我立即着手卸载大约50%我无偿安装的扩展,然后通过将我的大部分积极开发的Python内容提升到隔离的virtualenv项目目录中,再减少40%左右。

之后我感到非常愚蠢,因为我设法巧妙地使用花哨的分析工具误导自己,然后偶然发现了实际的解决方案 - 一个是由于我自己粗心疏忽造成的问题,同样也是如此。无论如何,它仍然可以咬住其他Pythonic开发人员,因此值得写。特此邀请您学习我在问题分类和诊断中的迂回冒险!

© www.soinside.com 2019 - 2024. All rights reserved.