【问题标题】:How to concatenate multiple Python source files into a single file?如何将多个 Python 源文件连接成一个文件?
【发布时间】:2009-10-16 22:30:50
【问题描述】:

(假设:应用程序启动时间绝对关键;我的应用程序启动很多;我的应用程序运行在导入速度比平时慢的环境中;需要导入许多文件;编译到.pyc 文件不可用。)

我想将定义模块集合的所有 Python 源文件连接到一个新的 Python 源文件中。

我希望导入新文件的结果就像我导入了一个原始文件(然后会导入更多原始文件,依此类推)。

这可能吗?

这是一个粗略的手动模拟,当提供模块“bar”和“baz”的源文件时,工具可能会产生什么。您将在部署代码之前运行这样的工具。

__file__ = 'foo.py'

def _module(_name):
    import types
    mod = types.ModuleType(name)
    mod.__file__ = __file__
    sys.modules[module_name] = mod
    return mod

def _bar_module():

    def hello():
        print 'Hello World! BAR'

    mod = create_module('foo.bar')
    mod.hello = hello
    return mod

bar = _bar_module()
del _bar_module

def _baz_module():

    def hello():
        print 'Hello World! BAZ'

    mod = create_module('foo.bar.baz')
    mod.hello = hello
    return mod

baz = _baz_module()
del _baz_module

现在你可以:

from foo.bar import hello
hello()

此代码未考虑导入语句和依赖项等内容。是否有任何现有代码可以使用这种或其他技术来组装源文件?

这与用于在发送到浏览器之前组装和优化 JavaScript 文件的工具非常相似,其中多个 HTTP 请求的延迟会损害性能。在这个 Python 案例中,在启动时导入数百个 Python 源文件的延迟会造成伤害。

【问题讨论】:

  • 您是否有任何数字可以证明这会影响解释器的启动时间?
  • 启动时间肯定是个问题。我希望这会加快速度。我已经澄清了问题中的限制。
  • 我也怀疑你会在这里看到加速。每次重新加载应用程序时,您仍然需要将 X 行代码加载到 VM 中。在花时间将您的模块统一到一个大文件中之前,我肯定会花时间确认这会加快您的速度。
  • "...在花时间将您的模块统一到一个大文件之前。"您错过了最后一行:“是否有任何 现有 代码可以使用这种或其他技术组装 源文件?”。我不建议编写这样的源代码,我想在部署之前处理现有的源代码。我也希望这是其他人尝试过的一种技术,这样我就不必编写它了:-)

标签: python google-app-engine import module concatenation


【解决方案1】:

如果这是在谷歌应用引擎上,如标签所示,请确保您使用的是这个成语

def main(): 
    #do stuff
if __name__ == '__main__':
    main()

因为 GAE 不会在每次请求时重新启动您的应用,除非 .py 已更改,它只是再次运行 main()

此技巧可让您编写 CGI 风格的应用程序而不会影响启动性能

AppCaching

如果处理程序脚本提供了 main() 例程,运行时环境也 缓存脚本。否则,该 为每个加载处理程序脚本 请求。

【讨论】:

  • 谢谢,但我已经这样做了。请注意,应用引擎通常只缓存一秒钟左右,每天有 14,000 次左右的机会缓存未命中,当使用许多具有复杂导入依赖关系的模块时,这种情况会更加严重。我对最大的启动性能非常感兴趣。
【解决方案2】:

我认为由于 Python 文件的预编译和一些系统缓存,您最终获得的速度将无法衡量。

【讨论】:

  • 您的意思是“无法衡量”吗?
  • 预编译为 .pyc 文件不可用。在这种特殊情况下,缓存并没有我希望的那么好。我已经在问题中澄清了这一点。
【解决方案3】:

这样做不太可能产生任何性能优势。您仍在导入相同数量的 Python 代码,只是在更少的模块中 - 而且您为此牺牲了所有模块化。

更好的方法是修改您的代码和/或库以仅在需要时导入内容,以便为每个请求加载最少的所需代码。

【讨论】:

  • 我不会牺牲所有的模块化,因为我建议在部署之前使用工具来处理我的源代码,这与现代 javascript 工具在部署之前组合、拆分和优化 javascript 的方式非常相似实际浏览器。说“编写你的代码只导入你需要的东西”是个好主意,但这排除了在核心 django 中使用 300 个 od 源文件,不包括 contrib 模块、外部库和我可能编写的任何东西。此外,您经常确实需要导入大量代码,因为您确实使用过它。
  • Nick,你在 Google 工作,你能描述一下在 App Engine 上加载部署用户代码的过程吗?这不仅仅是在加载多个模块时磁盘寻道的成本,就像在传统设置中那样,因为所有用户代码不会同时部署到所有实例。它实际上是如何完成的?它实际上是如何完成的?所有文件是一起部署的,一次一个,还是分批部署?自定义邮政编码如何工作?当您从 zip 加载一个模块时,所有模块都已加载,还是按需发生?等等……
  • 如果有 '300 奇数' 源文件对于进行按需导入来说是一个问题,如果你想将它们全部连接起来同样有问题 - 要么需要大量修改。使用像 Django 这样的大型框架的问题在于,正如您所观察到的,导入需要很长时间。不过,我怀疑您是否为任何给定请求使用了超过 20% 左右的模块。
  • 不确定您从哪里得到“按需”部署代码的想法 - 您可以使用 os.listdir 等函数来查看情况并非如此。同样,您可以自己检查 zipimport 代码以了解它是如何工作的。两者都相当简单 - 连接所有来源是一种“优化”,根本不可能有帮助。
  • “不知道你从哪里得到'按需'部署代码的想法 - 你可以使用 os.listdir 等函数来查看情况并非如此。”你是说数十万开发者编写的十万个应用程序同时持久部署到应用引擎中的数千台服务器的本地硬盘上的正常块大小,ext2/3/4文件系统簇? IE。应用引擎生产环境与一般的服务器设置基本相似?我看不出这种规模怎么可能……
【解决方案4】:

如果不处理这个问题,如果说你是对的,这种技术是否会提升你的环境,这就是我会做的。

我会列出我所有的模块,例如 my_files = ['foo', 'bar', 'baz']

然后我将使用 os.path 实用程序读取源目录下所有文件中的所有行并将它们全部写入一个新文件,过滤所有 import foo|bar|baz 行,因为所有代码现在都在一个文件中。

诅咒,最后在文件末尾添加来自__init__.py(如果有的话)的main()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 2022-01-19
    • 2015-08-08
    • 1970-01-01
    相关资源
    最近更新 更多