Python 是动态类型的——一个变量能够引用任何类型的对象,并且任意代码行都能够改变被引用对象的类型。这使得虚拟机难以在机器码层面优化代码的运行方式,因为它不知道哪种基础数据类型会用于将来的运算。让代码保持泛型就会让代码运行更慢。
在下面的例子中,v 或是一个浮点数,或是一对代表复数的浮点数。两个条件会先后在相同循环的不同位置发生,或者在相关代码的串行区域发生:
abs 函数会根据底层数据类型来以不同方式工作。对一个整数或浮点数来说,abs只是简单地把负值转换为正值来作为结果。对复数来说,abs 涉及对分量的平方和开平方根。
还是复数的例子,它的机器码涉及更多的指令并且会运行得更久。在对一个变量调用abs 之前,Python 首先不得不查看变量的类型,接着决定调用哪个函数版本——当做出很多重复调用的时候,这个开销会累积。
在CPU 密集型的代码区域内部,不改变变量类型的情况很常见。这就给了我们一个机会来做静态编译和加快代码运行。
一个扩展编译模块的简单方法涉及:
使用这个方法,setup.py 脚本调用Cython 把.pyx 文件编译成一个编译模块。在类UNIX 系统上,编译模块可能会是一个.so 文件;在Windows 上应该是一个.pyd(类DLL 的Python 库)。julia1.py:
#导入新编译模块到主代码中
import calculate # as defined in setup.py
def calc_pure_python(desired_width, max_iterations):
start_time = time.time()
output = calculate.calculate_z(max_iterations, zs, cs)
end_time = time.time()
secs = end_time - start_time
print("Took", secs, "seconds")
在cythonfn.pyx(可以从.py重命名)中为Cython的setup.py准备的未改动过的纯Python代码:
#cythonfn.pyx
def calculate_z_serial_purepython(maxiter, zs, cs):
output = [0] * len(zs)
for i in range(len(zs)):
n = 0
z = zs[i]
c = cs[i]
while n < maxiter and abs(z) < 2:
z = z * z + c
n += 1
output[i] = n
return output
<< · Back Index ·>>
今天聊聊美国电影《猎魔人:狼之噩梦》。 片名The Witcher: Nightmare of the Wolf (2021),别名巫师:狼之噩梦。 《猎 ...
近日在北、上、廣、深都相繼宣佈“認房不認貸”的政策後,各省也先後接龍官宣。咱們都知道這是放松房地產的政策,出瞭政策,願...