为啥将我的模块分成多个文件会使其变慢?
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
这样的小类,并且实例化这些类可能很昂贵,尽管在重构之前这不是问题。
在创建这些类时,它会从一个单独的文件中获取它们,它以 import
s 开头。
在耗时最长的部分(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__
方法。而且,在其他地方,幻数已经改变。我建议你先在别处寻找减速。
我不希望看到将代码库重构为单独文件的速度有任何差异,预计启动时间可能会略有(甚至很小)减少。我建议在拆分之前进行分支,实际上只将代码分成单独的文件,分析代码的性能,然后慢慢添加自拆分以来添加的代码,并每次进行分析,看看是什么减慢了你的代码。
【讨论】:
以上是关于为啥将我的模块分成多个文件会使其变慢?的主要内容,如果未能解决你的问题,请参考以下文章