假设一个计算密集型任务,计算的函数是形如:
计算N遍,N很大,那么在python中有多种实现方式最简单的两种方式:
import numpy as np
def original_complex_calc(x, y):
z = np.sqrt(x) * np.log(y) * np.power(x, y)
return z
import math
def original_complex_calc_math(x, y):
z = math.sqrt(x) * math.log(y) * math.pow(x, y)
return z
测试一下两者都循环运行1000w次的性能:
original_complex_calc 26.025455951690674
original_complex_calc_math 5.273261070251465
可以看到math库基础运算性能要比numpy要好,那有没有方法再提升一下性能呢,用cython掉c的库
python容易调用c/c++的代码,使用cython可以有两个好处:
1、首先需要写一个pyx文件,内部完成调用c库逻辑和计算逻辑
例如:calculation.pyx
# @Time : 2020/7/7
# @Author : 大太阳小白
# @Software: PyCharm
# @blog:https://blog.csdn.net/weixin_41579863
cdef extern from "math.h" nogil:
double sqrt(double)
double pow(double, double)
double log(double)
cdef double _complex_calc(double a, double b):
cdef double c = sqrt(a) * log(b) * pow(a,b)
return c
def complex_calc(a, b):
return _complex_calc(a, b)
2、其次写一个setup.py文件对calculation.pyx进行编译生成动态链接库,setup.py内容如下:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("calculation_cython", ["calculation.pyx"])]
setup(
name='calculation app',
language='c',
cmdclass={'build_ext': build_ext},
ext_modules=ext_modules,
)
使用命令生成链接库:
python setup.py build_ext --inplace
linux系统上生成.so文件,windows系统上生成.pyd文件
3.直接使用import调用编译好的动态链接库
import calculation_cython
if __name__ == '__main__':
a = 10.0
b = 10
print(calculation_cython.complex_calc(a, b))
最终性能测试一下
# @Time : 2020/7/7
# @Author : 大太阳小白
# @Software: PyCharm
# @blog:https://blog.csdn.net/weixin_41579863
import numpy as np
import calculation_cython
import time
import math
def original_complex_calc(x, y):
z = np.sqrt(x) * np.log(y) * np.power(x, y)
return z
def original_complex_calc_math(x, y):
z = math.sqrt(x) * math.log(y) * math.pow(x, y)
return z
if __name__ == '__main__':
a = 10.0 # 设置成浮点防止numpy的power出现溢出错误
b = 10
print(original_complex_calc_math(a, b))
print(original_complex_calc(a, b))
print(calculation_cython.complex_calc(a, b))
test_funs = [original_complex_calc, original_complex_calc_math, calculation_cython.complex_calc]
for func in test_funs:
start = time.time()
for _ in range(1000 * 10000):
func(a, b)
print(func.__name__, time.time() - start)
结果:
72814134002.11803
72814134002.11803
72814134002.11803
original_complex_calc 26.025455951690674
original_complex_calc_math 5.273261070251465
complex_calc 1.5478901863098145
性能再次提升!