Python 3类型提示用于性能优化

Jua*_*ote 8 python type-hinting python-3.x

PEP 484说"使用类型提示进行性能优化是留给读者的练习." 这告诉我,就像Common 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)
Run Code Online (Sandbox Code Playgroud)

我试图模仿的Common Lisp类比是:

(defun baselpi0 (n)
  (let ((baselsum 0.0d0))
    (loop for i from 1 to n do
      (setf baselsum (+ baselsum (/ 1.0 (* i i)))))
    (sqrt (* 6 baselsum))))

(defun baselpi1 (n)
  (let ((baselsum 0.0d0)
        (n (coerce n 'double-float)))
    (declare (type double-float baselsum n)
         (optimize (speed 3) (safety 0) (debug 0)))
    (loop for i from 1.0d0 to n do
          (setf baselsum (+ baselsum (/ 1.0d0 (* i i)))))
    (sqrt (* 6.0d0 baselsum))))

(time (princ (baselpi0 1000000000)))
(time (princ (baselpi1 1000000000)))
(exit)
Run Code Online (Sandbox Code Playgroud)

在我的机器上,使用sbcl运行的lisp版本对于慢版本需要22秒,对于类型提示版本需要4秒,与C相同.对于朴素版本,CPython需要162秒,对于类型提示版本需要141秒.Pypy在不到5秒的时间内运行非类型提示版本,但是库支持对我的项目来说还不够好.

有没有办法可以改进我的类型暗示版本,以获得更接近lisp或Pypy的性能?

Jim*_*ard 8

速度差异不是由于类型提示.Python 目前,在可预见的未来,只会丢弃您提供的任何提示,并继续像往常一样动态执行.

这是因为在一种情况下,您在整个代码中使用浮动算法(这会导致更快的执行),而在另一种情况下则不会.

例证:baselpi1改为:

def baselpi1(n : int) -> float:
    n = float(n)
    baselsum  = 0
    i = 1
    while i < n:
        baselsum += 1.0 / (i * i)
        i += 1
    return math.sqrt(6.0 * baselsum)
Run Code Online (Sandbox Code Playgroud)

现在来看看执行时间:

3.141591698659554
0.2511475086212158
3.141591698659554
0.4525010585784912
Run Code Online (Sandbox Code Playgroud)

是的,它慢了.

  • @Juanote不,不是一般的.你可以在你自己的代码中利用它们,只要你弄清楚如何去做,这就是练习.但是你不能指望别人的代码(读取:CPython)对类型提示做任何事情,除非它被记录下来. (3认同)