【发布时间】:2011-02-08 10:10:09
【问题描述】:
我正在优化一些代码,其主要瓶颈在于运行并访问非常大的类似结构的对象列表。目前我正在使用命名元组,以提高可读性。但是一些使用“timeit”的快速基准测试表明,在性能是一个因素的情况下,这确实是错误的方法:
具有 a、b、c 的命名元组:
>>> timeit("z = a.c", "from __main__ import a")
0.38655471766332994
类使用__slots__,带有a、b、c:
>>> timeit("z = b.c", "from __main__ import b")
0.14527461047146062
带有键 a、b、c 的字典:
>>> timeit("z = c['c']", "from __main__ import c")
0.11588272541098377
具有三个值的元组,使用常量键:
>>> timeit("z = d[2]", "from __main__ import d")
0.11106188992948773
使用常量键列出三个值:
>>> timeit("z = e[2]", "from __main__ import e")
0.086038238242508669
具有三个值的元组,使用本地键:
>>> timeit("z = d[key]", "from __main__ import d, key")
0.11187358437882722
使用本地键列出三个值:
>>> timeit("z = e[key]", "from __main__ import e, key")
0.088604143037173344
首先,这些小的timeit 测试有什么会导致它们无效的吗?我分别运行了几次,以确保没有随机系统事件将它们抛出,结果几乎相同。
似乎字典在性能和可读性之间提供了最佳平衡,类排在第二位。这很不幸,因为就我的目的而言,我还需要对象是类似序列的;因此我选择了命名元组。
列表要快得多,但常量键是不可维护的;我必须创建一堆索引常量,即 KEY_1 = 1、KEY_2 = 2 等,这也不理想。
我是否坚持这些选择,或者我错过了其他选择?
【问题讨论】:
-
如果性能如此重要,为什么不使用 C?
-
@Skilldrick:这只是一个较大程序的一小部分,它受益于用 Python 编写。将这部分重写为 C 扩展是一种选择,但有些不可取,因为其他代码也涉及数据,使事情变得有点复杂。性能很重要,但不是那么至关重要;如果不是因为降低了可维护性,我会对列表提供的 4 倍改进感到非常满意。在决定走哪条路之前,我只是在寻找其他选择。
-
@Warren P:是的;我不会过早地优化。这是一个非常紧凑的循环,其中简单地访问结构是工作的重要部分。这是程序中最慢的剩余循环。即使是适度的改进也可以将实际运行时间缩短一两秒。由于整个事情是重复的,所以加起来。
-
也可以考虑尝试 pypy。使用 pypy,我在不同案例之间的表现没有任何差异。
-
numpy 具有某种结构,在某些情况下可以提供比 C 更好的性能。 docs.scipy.org/doc/numpy/user/basics.rec.html这个和YMMV我没试过!
标签: python performance data-structures