如何加速Python启动和/或减少加载库时的文件搜索时间?

9 投票
2 回答
4426 浏览
提问于 2025-04-17 19:29

我有一个框架,里面有不同的工具,都是用Python写的,适合多人使用。

第一次登录系统并执行一个命令时,显示几行帮助信息需要6秒钟。如果我立刻再执行一次同样的命令,只需要0.1秒。过了几分钟后,又变回6秒了。(这证明了短期缓存的存在)

这个系统运行在GPFS上,所以磁盘的读写速度应该没问题,不过由于系统里的文件数量很多,访问速度可能会比较慢。

strace -e open python tool | wc -l

启动工具时显示有2154个文件被访问。

strace -e open python tool | grep ENOENT | wc -l

显示有1945个缺失的文件在被查找。(如果你问我,这个命中/未命中比率非常糟糕 :-)

我感觉加载这个工具所花的时间主要是用来查询GPFS上所有这些文件的,而这些文件在下一次调用时会被缓存(可能是在系统层面或GPFS层面),但我不知道怎么测试或证明这一点。

我没有系统的根权限,只能写入GPFS和/tmp目录。

有没有办法改善这个python查找缺失文件的过程呢?

有没有简单的方法可以测试这个?(在/tmp上重新安装所有东西并不简单,因为涉及很多包,虚拟环境也没什么帮助,因为它只是链接了GPFS系统上的文件。)

当然,一个选择是有一个守护进程来分叉,但这远不是“简单”,而且会是最后的解决方案。

谢谢你的阅读。

2 个回答

2

在Python 2中,程序会先在当前的包里面找模块。如果你的库代码里有很多对顶层模块的引用,Python会优先在当前包里查找这些模块。例如,如果包foo.bar想要引入os模块,Python会首先去找foo/bar/os.py这个文件。如果找不到,Python会记住这个查找失败的情况。

而在Python 3中,默认的查找方式变成了绝对导入;你可以在Python 2.5及以上版本中,针对每个模块切换到绝对导入,方法是:

from __future__ import absolute_import

另一个可能导致查找失败的原因是加载.pyc字节码缓存文件;如果这些文件因为某种原因缺失(比如当前Python进程没有写入文件系统的权限),那么每次运行时Python都会继续寻找这些文件。你可以使用compileall模块来创建这些缓存:

python -m compileall /path/to/directory/with/pythoncode

前提是你要用正确的写入权限来运行这个命令。

2

你可以试试用imp模块。特别是里面有一个函数:
imp.find_module(module, path),你可以在这里找到更多信息:http://docs.python.org/2.7/library/imp.html

至少这个例子(见下面)能减少打开文件的系统调用次数,相比直接用'import numpy, scipy'来说:(更新:不过看起来这样做并不能显著减少系统调用次数……)

import imp
import sys


def loadm(name, path):
    fp, pathname, description = imp.find_module(name,[path])
    try:
        _module = imp.load_module(name, fp, pathname, description)
        return _module
    finally:
        # Since we may exit via an exception, close fp explicitly.
        if fp:
            fp.close()


numpy = loadm("numpy", "/home/username/py-virtual27/lib/python2.7/site-packages/")
scipy = loadm("scipy", "/home/username/py-virtual27/lib/python2.7/site-packages/")

我想你最好检查一下你的PYTHONPATH是否为空或者很小,因为这也会增加加载时间。

撰写回答