一、简介
- 本文主要对比纯python代码、cython代码以及python调用c库运行效率对比。
- 文件结构:
二、代码
1. python代码
get_angle_python.py
import math
def get_angle(x,y):
angle = 123
if y == 0 :
if x < 0:
angle = 180
else:
angle = 0
if x == 0 :
if y > 0:
angle = 90
else:
angle = 270
else:
tan_yx = abs(y)/abs(x)
if y > 0 and x < 0:
angle = 180 - math.atan(tan_yx)*180/math.pi #90-180
elif y > 0 and x > 0:
angle = math.atan(tan_yx)*180/math.pi #0-90
elif y < 0 and x < 0:
angle = 180 + math.atan(tan_yx)*180/math.pi #180-270
elif y < 0 and x > 0:
angle = 360- math.atan(tan_yx)*180/math.pi #270-360
return angle
2. cython代码
get_angle_cython.pyx
cimport cython
import math
@cython.boundscheck(False)
@cython.wraparound(False)
cdef float _get_angle(float x, float y):
cdef float angle
cdef float tan_yx
angle = 123
if y == 0 :
if x < 0:
angle = 180
else:
angle = 0
if x == 0 :
if y > 0:
angle = 90
else:
angle = 270
else:
tan_yx = abs(y)/abs(x)
if y > 0 and x < 0:
angle = 180 - math.atan(tan_yx)*180/math.pi #90-180
elif y > 0 and x > 0:
angle = math.atan(tan_yx)*180/math.pi #0-90
elif y < 0 and x < 0:
angle = 180 + math.atan(tan_yx)*180/math.pi #180-270
elif y < 0 and x > 0:
angle = 360- math.atan(tan_yx)*180/math.pi #270-360
return angle
def get_angle(float x, float y):
return _get_angle(x, y)
setup_cython.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
extension = Extension(
"get_angle_cython",
["get_angle_cython.pyx"],
# libraries=["method"]
)
setup(
ext_modules=cythonize([extension]),
)
命令行
python setup_cython.py build_ext --inplace
编译产生get_angle_cython.c
和get_angle_cython.pyd
(windows)或get_angle_cython.so
(linux)文件。
引用时import get_angle_cython
即可。
3. python调用c库代码
get_angle.h
float _get_angle(float x, float y);
get_angle.c
#include "get_angle.h"
#include <math.h>
#define pi (2*acos(0.0))
// 方向向量转化为角度
float _get_angle(float x, float y){
float angle = 123;
if(y == 0){
if(x < 0)
angle = 180;
else
angle = 0;
}
if(x == 0){
if(y > 0)
angle = 90;
else
angle = 270;
}
else{
float tan_yx = fabs(y)/fabs(x);
if (y > 0 && x < 0){
angle = 180 - atan(tan_yx)*180/pi; //90-180
}else if(y > 0 && x > 0){
angle = atan(tan_yx)*180 / pi; //0-90
}else if (y < 0 && x < 0){
angle = 180 + atan(tan_yx)*180/pi; //180-270
}else if (y < 0 && x > 0){
angle = 360- atan(tan_yx)*180/pi; //270-360
}
}
return angle;
}
get_angle_c.pyx
cdef extern from "get_angle.h":
float _get_angle(float x, float y)
def get_angle(float x, float y):
return _get_angle(x, y)
setup_c.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy
setup(ext_modules = cythonize(Extension(
'get_angle_c',
sources=['get_angle_c.pyx', 'get_angle.c'],
language='c',
# include_dirs=[numpy.get_include()],
library_dirs=[],
# libraries=["method"],
extra_compile_args=[],
extra_link_args=[]
)))
命令行
python setup_c.py build_ext --inplace
编译产生get_angle_c.c
和get_angle_c.pyd
(windows)或get_angle_c.so
(linux)文件。
引用时import get_angle_c
即可。
3. 结果测试
test.py
# test.py
import get_angle_python
import get_angle_cython
import get_angle_c
a = get_angle_python.get_angle(48, 10)
b = get_angle_cython.get_angle(48, 10)
c = get_angle_c.get_angle(48, 10)
print("a = ", a)
print("b = ", b)
print("c = ", c)
运行结果:
精度损失跟float接收double有关。
4. 效率测试
使用jupyter运行如下代码:
-
导入模块:
import get_angle_python import get_angle_cython import get_angle_c
-
运行测试函数:
%timeit -n 100 -r 3 get_angle_python.get_angle(48, 10) %timeit -n 100 -r 3 get_angle_cython.get_angle(48, 10) %timeit -n 100 -r 3 get_angle_c.get_angle(48, 10)
-
运行结果:
Windows:
Ubuntu: