【问题标题】:Class instantiation slower in Python 3 than Python 2Python 3 中的类实例化比 Python 2 慢
【发布时间】:2016-02-07 22:19:21
【问题描述】:

我偶然注意到,一个从大型数据文件生成类的简单程序在 Python 2.7 和 3.5 中运行得更快。我读到here 说使用“无限精度”整数是导致简单枚举速度变慢的原因,但即使我尝试了一个简单的测试来实例化这个类,我发现 Python 3 的速度要慢得多:

class Benchmark(object):
    def __init__(self):
        self.members = ['a', 'b', 'c', 'd']


def test():
    test = Benchmark()

if __name__ == '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test"))

我认为这可能与每个类实例的大小有关,但 Python 3 实例小于 2(56 对 64)

$python3 benchmarks.py
0.7017288669958361
$python benchmarks.py
0.508942842484

我在这个主题上尝试了许多变体,包括在不同的机器上使用 3.4,但仍然得到相同的结果。有什么想法吗?

【问题讨论】:

  • 链接的副本是关于 Python 3 比 Python 2 快,而这个问题是相反的。投票重新开放。
  • 如果只运行timeit("Benchmark()", ...),你会得到什么?听起来您真的不想为函数调用、变量赋值等计时。如果您只为列表创建计时呢?
  • 我得到的结果和你一样,直到我把这个减少到只剩下班级。我只做了class A: pass,然后将您的timeit 调用更改为timeit("A()", setup="from __main__ import A"),Py2 的速度是Py3 的两倍。无论最初的结果如何,我怀疑这与对象实例化有关。如果我这样做class A(object): pass,结果将无法区分。
  • 实例创建真的是任何真实代码的瓶颈吗?我猜你对你的班级所做的任何其他工作都会比班级创建慢几个数量级,所以我不担心需要多长时间。如果您分析了您的代码并发现这确实是一个问题,那么当然,您应该对其进行调查,但我怀疑情况是否如此。
  • 我只是好奇,在 20 秒内运行某些东西而不是 Py2 的 5 秒,但 Py3 应该更慢似乎有点奇怪。我将它剥离为一个完全空的类的时间实例化,我仍然发现 3 比 2 慢,在 macbook pro 和运行 ubuntu 的 i7-4790K 4.00GHz 处理器和 16gb ram 的工作机器上,两个版本都安装在同一个地方和一切。

标签: python class python-3.x instance


【解决方案1】:

你不是在测量类实例化时间,你是在测量类实例化,加上赋值,加上列表创建,......

这是一个正确的基准:

$ python -m timeit -s 'class C(object): pass' 'C()'
10000000 loops, best of 3: 0.0639 usec per loop
$ python3 -m timeit -s 'class C(object): pass' 'C()'
10000000 loops, best of 3: 0.0622 usec per loop

如您所见,Python 3 明显更快。

【讨论】:

  • 另外,Python 3 节省的内存比你想象的要多;实例的总大小开销是实例的sys.getsizeof 加上其__dict__sys.getsizeof(除非__dict__ 在C 层被抑制或使用__slots__)。 Python 3.3 introduced shared key dictionaries,所以除了对象结构缩小一点(x64 上为 8 个字节)之外,单个属性实例的 __dict__ 的大小下降了约 3 倍(在我的 Linux x64 机器上,从 280 字节到 96字节)。大量实例节省大量资金。
  • Andrea:您可能希望让测试分配一个编译时文字成员;虽然列表构造、函数调用和项目分配并不是一个好的测试的适当部分,但在__init__ 中分配至少一个实例属性应该是合理测试的一部分。
  • @ShadowRanger:如果你在基准测试中混合了太多东西,你永远不会发现哪里出了问题。这个问题是一个明确的例子:OP 认为类实例化较慢,但事实并非如此。
  • 是的,我想说的是,对于大多数人来说,初始化成员是“类实例化”的一部分。只需在字节码中使用可以用LOAD_CONST 表示的文字(例如,空的tuple()int0),您将限制其他混杂因素,同时仍然测试相当重要的部分实例创建。共享密钥字典可能会稍微减慢实例的创建速度,但其他情况下的好处(内存使用量更低,使用速度通常更快)通常是值得的。
  • 是的,在 shx2 对原始帖子发表评论后,我意识到这一点。将 python3.5 与 2.7.1 进行比较,我仍然遇到同样的问题。 $ python -m timeit -s 'class C(object): pass' 'C()' 10000000 loops, best of 3: 0.0896 usec per loop $ python3 -m timeit -s 'class C(object): pass' 'C()' 10000000 loops, best of 3: 0.106 usec per loop
猜你喜欢
  • 2017-11-05
  • 2014-06-20
  • 2015-10-11
  • 1970-01-01
  • 2013-01-21
  • 2012-04-06
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多