如何使 python 代码的求和速度更快?
How do I make my python code for summing much faster?
下面的代码是从下限 2 求和的定义函数,我改变了和的上限,因为我想找出和收敛的地方。我发现上限越大代码运行s越慢。对于任何大的上限值,如何使此代码 运行 快速?代码如下:
def h(i):
x = (-1)**(i+1)
y = 1000000000-(i-1)
z = (log(i))**20
return x*y*z
gx = sum(h(i) for i in range (2, 1000000000+1))
d_gx = gx/1000000000
print(d_gx)
Numba 是一个 python 库,用于即时优化纯 python 代码,无需外部编译步骤。
这里要介绍的两个重要函数是numba.njit
和numba.vectorize
,它们都是装饰器。 njit
优化任意纯函数,vectorize
使函数在标量和 ndarray 上运行。
In [1]: from numba import vectorize, njit; from math import log
In [2]: def h(i):
...: x = (-1)**(i+1)
...: y = 1000000000-(i-1)
...: z = (log(i))**20
...: return x*y*z
...:
In [3]: %timeit sum(h(i) for i in range (2, 1000000+1))
646 ms ± 9.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
正如您在此处看到的那样,您的函数的简单实现平均需要 646 毫秒,减少了输入量 space。我们可以通过调整您的功能来改进这一点:
In [4]: jit_h = njit()(h)
In [5]: %timeit sum(jit_h(i) for i in range (2, 1000000+1))
179 ms ± 3.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
我们已将其缩短为 179 毫秒,与原来的 646 毫秒相比有了巨大的改进。因为 for 循环很慢,我们可以尝试使用 numpy 数组作为输入来向量化操作:
In [6]: vectorize_h = vectorize()(h)
In [7]: %timeit sum(vectorize_h(i) for i in range (2, 1000000+1))
657 ms ± 4.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
正如预期的那样,矢量化输入允许传递标量,但不会显着提高性能——事实上,它有点慢!如果我们对整个 numpy 数组进行操作会怎么样?
In [8]: import numpy as np
In [9]: %timeit sum(vectorize_h(np.arange(2,1000000+1)))
149 ms ± 1.78 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
最后,如果我们用 numpy ndarray sum 替换 sum
内置函数会怎样?
In [10]: %timeit vectorize_h(np.arange(2,1000000+1)).sum()
17.2 ms ± 207 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
进一步减少到 17.2 毫秒 -- 与原始实现相比有了巨大的改进。
下面的代码是从下限 2 求和的定义函数,我改变了和的上限,因为我想找出和收敛的地方。我发现上限越大代码运行s越慢。对于任何大的上限值,如何使此代码 运行 快速?代码如下:
def h(i):
x = (-1)**(i+1)
y = 1000000000-(i-1)
z = (log(i))**20
return x*y*z
gx = sum(h(i) for i in range (2, 1000000000+1))
d_gx = gx/1000000000
print(d_gx)
Numba 是一个 python 库,用于即时优化纯 python 代码,无需外部编译步骤。
这里要介绍的两个重要函数是numba.njit
和numba.vectorize
,它们都是装饰器。 njit
优化任意纯函数,vectorize
使函数在标量和 ndarray 上运行。
In [1]: from numba import vectorize, njit; from math import log
In [2]: def h(i):
...: x = (-1)**(i+1)
...: y = 1000000000-(i-1)
...: z = (log(i))**20
...: return x*y*z
...:
In [3]: %timeit sum(h(i) for i in range (2, 1000000+1))
646 ms ± 9.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
正如您在此处看到的那样,您的函数的简单实现平均需要 646 毫秒,减少了输入量 space。我们可以通过调整您的功能来改进这一点:
In [4]: jit_h = njit()(h)
In [5]: %timeit sum(jit_h(i) for i in range (2, 1000000+1))
179 ms ± 3.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
我们已将其缩短为 179 毫秒,与原来的 646 毫秒相比有了巨大的改进。因为 for 循环很慢,我们可以尝试使用 numpy 数组作为输入来向量化操作:
In [6]: vectorize_h = vectorize()(h)
In [7]: %timeit sum(vectorize_h(i) for i in range (2, 1000000+1))
657 ms ± 4.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
正如预期的那样,矢量化输入允许传递标量,但不会显着提高性能——事实上,它有点慢!如果我们对整个 numpy 数组进行操作会怎么样?
In [8]: import numpy as np
In [9]: %timeit sum(vectorize_h(np.arange(2,1000000+1)))
149 ms ± 1.78 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
最后,如果我们用 numpy ndarray sum 替换 sum
内置函数会怎样?
In [10]: %timeit vectorize_h(np.arange(2,1000000+1)).sum()
17.2 ms ± 207 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
进一步减少到 17.2 毫秒 -- 与原始实现相比有了巨大的改进。