python的性能_python性能特征

python的编译器故意地非常简单——这使得它快速且高度可预测。除了一些持续的折叠之外,它基本上生成了忠实地模仿源代码的字节码。已经有人建议了

dis

这确实是一个很好的方法来查看您得到的字节码——例如,如何

for i in [1, 2, 3]:

实际上不是不断地进行折叠,而是动态地生成文本列表,而

for i in (1, 2, 3):

(循环文本元组而不是文本列表)

能够持续折叠(原因:列表是一个可变的对象,为了保持“非常简单”的任务语句,编译器不需要检查这个特定的列表是否从未被修改过,所以

能够

优化成一个元组)。

所以这里有足够的空间进行手动微优化——尤其是提升。即重写

for x in whatever():

anobj.amethod(x)

作为

f = anobj.amethod

for x in whatever():

f(x)

保存重复的查找(编译器不检查

anobj.amethod

实际上可以改变

anobj

's bindings&c,以便下次需要新的查找--它只是做一些非常简单的事情,即不提升,这可以保证正确性,但绝对不能保证燃烧的速度;-)。

这个

timeit

模块(最好在shell提示imho中使用)使得测量编译和字节码解释的整体效果变得非常简单(只要确保要测量的代码片段没有影响计时的副作用,因为

timeit

在循环中反复运行;-)。例如:

$ python -mtimeit 'for x in (1, 2, 3): pass'

1000000 loops, best of 3: 0.219 usec per loop

$ python -mtimeit 'for x in [1, 2, 3]: pass'

1000000 loops, best of 3: 0.512 usec per loop

您可以看到重复列表构建的成本——并通过尝试一个小的调整来确认这确实是我们观察到的:

$ python -mtimeit -s'Xs=[1,2,3]' 'for x in Xs: pass'

1000000 loops, best of 3: 0.236 usec per loop

$ python -mtimeit -s'Xs=(1,2,3)' 'for x in Xs: pass'

1000000 loops, best of 3: 0.213 usec per loop

将Iterable的结构移动到

-s

设置(只运行一次,不定时)表明,元组上的循环速度稍快(可能10%),但第一对的大问题(列表速度比元组慢100%以上)主要与构造有关。

装备

时计

并且知道编译器在优化时故意非常简单,我们可以很容易地回答您的其他问题:

下列操作有多快

(相对)

* Function calls

* Class instantiation

* Arithmetic

* 'Heavier' math operations such as sqrt()

$ python -mtimeit -s'def f(): pass' 'f()'

10000000 loops, best of 3: 0.192 usec per loop

$ python -mtimeit -s'class o: pass' 'o()'

1000000 loops, best of 3: 0.315 usec per loop

$ python -mtimeit -s'class n(object): pass' 'n()'

10000000 loops, best of 3: 0.18 usec per loop

所以我们看到:实例化一个新样式的类和调用一个函数(都是空的)的速度大致相同,而实例化可能有一个很小的速度差,可能是5%;实例化一个旧样式的类的速度最慢(大约是50%)。微小的差别,如5%或更少当然可能是噪音,所以每次重复几次是明智的;但像50%的差别肯定远远超过噪音。

$ python -mtimeit -s'from math import sqrt' 'sqrt(1.2)'

1000000 loops, best of 3: 0.22 usec per loop

$ python -mtimeit '1.2**0.5'

10000000 loops, best of 3: 0.0363 usec per loop

$ python -mtimeit '1.2*0.5'

10000000 loops, best of 3: 0.0407 usec per loop

在这里我们看到:打电话

sqrt

比由运算符执行相同的计算慢(使用

**

通过调用一个空函数的成本来提高操作人员的能力;所有的算术操作人员的速度都大致相同,在噪声范围内(3或4纳秒的微小差别绝对是噪声;-)。检查持续折叠是否会干扰:

$ python -mtimeit '1.2*0.5'

10000000 loops, best of 3: 0.0407 usec per loop

$ python -mtimeit -s'a=1.2; b=0.5' 'a*b'

10000000 loops, best of 3: 0.0965 usec per loop

$ python -mtimeit -s'a=1.2; b=0.5' 'a*0.5'

10000000 loops, best of 3: 0.0957 usec per loop

$ python -mtimeit -s'a=1.2; b=0.5' '1.2*b'

10000000 loops, best of 3: 0.0932 usec per loop

…我们看到事实确实如此:如果将两个数字中的一个或两个都作为变量进行查找(这会阻止不断折叠),我们将支付“现实”成本。变量查找有其自身的成本:

$ python -mtimeit -s'a=1.2; b=0.5' 'a'

10000000 loops, best of 3: 0.039 usec per loop

不管怎样,当我们试图测量这么小的时间时,这绝不是微不足道的。的确

常数

查找也不是免费的:

$ python -mtimeit -s'a=1.2; b=0.5' '1.2'

10000000 loops, best of 3: 0.0225 usec per loop

如您所见,虽然比变量查找小,但它是相当可比的——大约有一半。

如果(有了仔细的分析和测量)您决定计算的一些核心非常需要优化,我建议您尝试

cython

--这是一个C/python合并,它尝试着像python一样整洁,像c一样快,虽然它不能100%达到目标,但它确实是一个很好的拳头(特别是,它使二进制代码比前代语言快得多,

pyrex

以及比它更富有一点)。对于性能的最后几个百分点,您可能仍然希望使用C(或者在某些特殊情况下使用汇编/机器代码),但这将是非常罕见的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值