pep484说“将类型提示用于性能优化是留给读者的练习。”这对我来说,就像普通的Lisp一样,当我发誓我知道自己在做什么时,类型声明可以用来在性能密集型函数中搁置类型分派。为了亲自尝试,我创建了一个小基准,用p系列计算pi。首先我用天真的方式来做,然后我试着变得聪明,利用类型提示来提高性能:
import math
import time
def baselpi0(n):
baselsum = 0;
for i in range(1,n):
baselsum += 1.0 / (i * i)
return math.sqrt(6.0 * baselsum)
def baselpi1(n : int) -> float:
n = float(n)
baselsum = 0.0
i = 1.0
while i < n:
baselsum += 1.0 / (i * i)
i += 1.0
return math.sqrt(6.0 * baselsum)
start = time.time()
print(baselpi0(1000000000))
end = time.time()
print(end - start)
start = time.time()
print(baselpi1(1000000000))
end = time.time()
print(end - start)
我试图模仿的常见Lisp类比是:
^{pr2}$在我的机器上,使用sbcl运行的lisp版本对于慢版本需要22秒,对于类型提示版本需要4秒,与C.CPython对于天真版本需要162秒,对于类型提示版本需要141秒。Pypy只需不到5秒钟就可以运行非类型提示版本,但是库支持对于我的项目来说还不够好。在
有没有一种方法可以改进我的类型提示版本,使性能更接近lisp或Pypy?在
速度差不是由类型暗示引起的。Python目前以及在可预见的将来,just会丢弃您提供的任何提示,并继续像以前一样动态执行。在
这是因为在一种情况下,您在整个代码中使用浮动算术(这会导致更快的执行速度),而在另一种情况下则不使用
例如:将
baselpi1
更改为以下内容:看看现在的执行时间:
^{pr2}$是的,速度慢得多。在
如果您需要进行大量的数值计算,那么^{} 通常是一个不错的选择。Numpy可以处理较低级别的数据类型(例如固定宽度的整数python的是无界的)。这会给你一种暗示你感兴趣的类型。由于numpy设计用于处理具有已知类型的数组中的大量数据,因此它可以在整个数组上高效地执行相同的操作。这也允许numpy与那些SIMD指令的CPU很好地工作(我不知道没有SIMD的现代CPU)。在
我通常会这样重写您的函数:
但是,对于大的
^{pr2}$n
,您将没有足够的内存。您需要添加一些额外的代码来批处理操作。即:我5.2秒后在我的笔记本上得到结果。虽然我没有测试您使用的
n
的值,但是对于较低的n
来说,numpy版本的速度要快20倍以上。在相关问题 更多 >
编程相关推荐