为啥将我的模块分成多个文件会使其变慢?

Posted

技术标签:

【中文标题】为啥将我的模块分成多个文件会使其变慢?【英文标题】:Why does separating my module into multiple files make it slower?为什么将我的模块分成多个文件会使其变慢? 【发布时间】:2016-09-09 04:56:09 【问题描述】:

我制作了一个 Python 模块 (swood),直到最近,它还是一个包含许多类的大文件。在将相关类重构为单独的文件后,一切仍然有效,尽管速度慢了 50% 左右。我假设,如果有的话,它会变得更快一点,因为 Python 可以更有效地缓存每个文件的字节码,从而缩短启动时间。

我正在使用 CPython 运行此代码(尚未使用 PyPy 及其同类产品进行测试)。我在旧版本和重构版本上运行了line_profiler,每行所花费的处理时间百分比在重构前后大致相同。

以下是关于我的程序的一些可能与它有关的事情:

它生成了很多像 Note 这样的小类,并且实例化这些类可能很昂贵,尽管在重构之前这不是问题。 在创建这些类时,它会从一个单独的文件中获取它们,它以 imports 开头。 在耗时最长的部分(scaling 和 mixing 音频)中发生了大量基于 numpy 的数组操作 如果它们在 7.5 秒内被使用超过 3 次,我有一个缓存,用于存储缩放的音符。 (code)

是什么导致我的代码在将其分成多个文件后什么都不做?

【问题讨论】:

你可能在某个时候搞砸了。将您的代码分成更多模块会导致加载所有模块需要更长的时间,但这种减速会比您报告的要低得多。一目了然,没有什么让我觉得很慢,但我确实看到了一些奇怪的东西(比如__hash__没有__eq__),这表明你的代码可能不是没有错误的。 【参考方案1】:

在进行了一些基准测试之后,我怀疑这是其中的一件事:必须从另一个模块访问函数/类意味着要再次查找 Python 解释器,并且在一些紧密的循环中会出现轻微的减速。 The Python wiki has something about this, too:

避免点...

假设您不能使用地图或列表推导式?你可能会被卡住 与 for 循环。 for 循环示例还有另一个效率低下的地方。两个都 newlist.append 和 word.upper 是函数引用,它们是 每次通过循环重新评估。原始循环可以是 替换为:

upper = str.upper
newlist = []
append = newlist.append
for word in oldlist:
    append(upper(word))

【讨论】:

【参考方案2】:

您的重构似乎不仅仅是将类移动到不同的文件中。例如,UncachedWavFile 丢失了一个 __setitem__ 方法。而且,在其他地方,幻数已经改变。我建议你先在别处寻找减速。

我不希望看到将代码库重构为单独文件的速度有任何差异,预计启动时间可能会略有(甚至很小)减少。我建议在拆分之前进行分支,实际上只将代码分成单独的文件,分析代码的性能,然后慢慢添加自拆分以来添加的代码,并每次进行分析,看看是什么减慢了你的代码。

【讨论】:

以上是关于为啥将我的模块分成多个文件会使其变慢?的主要内容,如果未能解决你的问题,请参考以下文章

从 .dae 加载顶点会使我的程序变慢,为啥?

为啥使用 DOMDocument 会使网站加载速度变慢?

为啥 subselect 会使 SQL 请求变慢?

为啥codeigniter会变慢?

在 C 中读取大缓冲区 - 高效技术

为啥在 subView 中添加 UILabel 会使其像素化