先抱怨下Windows 64Bit下的交叉编译简直折磨死人,倒腾了几天之后决定还是切到Linux下算了。虚拟机虽然不给力,但是好歹能看出来优化后的结果。本文没什么讲的,只是将上文说到的扫雷机的进化过程中耗时最长的函数用C重新写一遍后比较下运行速度,废话不多说,直接贴代码,看结果。
Python代码
原来判断两条直线AB和CD的python代码是长下面这样的,原理不再赘述。
def LineIntersection2D(Ax, Ay, Bx, By, Cx, Cy, Dx, Dy):
Bx_Ax = Bx-Ax
Dy_Cy = Dy-Cy
By_Ay = By-Ay
Dx_Cx = Dx-Cx
Ay_Cy = Ay-Cy
Dx_Cx = Dx-Cx
Ax_Cx = Ax-Cx
Dy_Cy = Dy-Cy
Denominator = float(Bx_Ax*Dy_Cy - By_Ay*Dx_Cx)
if -0.000005<Denominator<0.000005: # rDenominator == sDenominator
# lines are parallel
return -1.0
rNumerator = Ay_Cy*Dx_Cx - Ax_Cx*Dy_Cy
sNumerator = Ay_Cy*Bx_Ax - Ax_Cx*By_Ay
r = rNumerator / Denominator
s = sNumerator / Denominator
#print rNumerator, sNumerator, Denominator, r, s
if 0<=r<=1.0 and 0<=s<=1.0:
return r
else:
return -1.0
再重复下python的代码的运行效率如下:
C代码
LineIntersection2D用Python来运行实在是太慢了,用C改写后的代码如下,可以看到逻辑上是完全一样的:
float LineIntersection2D(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float Dx, float Dy) {
float Bx_Ax = Bx-Ax;
float Dy_Cy = Dy-Cy;
float By_Ay = By-Ay;
float Dx_Cx = Dx-Cx;
float Ay_Cy = Ay-Cy;
float Ax_Cx = Ax-Cx;
float retVal = -1.0;
float Denominator = (Bx_Ax*Dy_Cy - By_Ay*Dx_Cx);
if (-0.000005<Denominator && Denominator<0.000005){
return retVal;
}
float rNumerator = Ay_Cy*Dx_Cx - Ax_Cx*Dy_Cy;
float sNumerator = Ay_Cy*Bx_Ax - Ax_Cx*By_Ay;
float r = rNumerator / Denominator;
float s = sNumerator / Denominator;
//printf("%f, %f, %f, %f\n", rNumerator, sNumerator, r, s);
if(0<=r && r<=1.0 && 0<=s && s<=1.0){
retVal = r;
}
return retVal;
}
用C重写后的速度如下:
局部的函数速度提高了非常多,但是代码中还有很多其他需要优化的地方,总体速度只提升了大概60%。不过本系列只讨论遗传算法和神经网络,就不再深究python代码的瓶颈在哪儿了。(其实是水平太差又懒,不知道也懒得深究 >_<)
附上C代码的完整代码凑凑字数. :)
CCollision.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "Python.h"
float LineIntersection2D(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float Dx, float Dy) {
float Bx_Ax = Bx-Ax;
float Dy_Cy = Dy-Cy;
float By_Ay = By-Ay;
float Dx_Cx = Dx-Cx;
float Ay_Cy = Ay-Cy;
float Ax_Cx = Ax-Cx;
float retVal = -1.0;
float Denominator = (Bx_Ax*Dy_Cy - By_Ay*Dx_Cx);
if (-0.000005<Denominator && Denominator<0.000005){
return retVal;
}
float rNumerator = Ay_Cy*Dx_Cx - Ax_Cx*Dy_Cy;
float sNumerator = Ay_Cy*Bx_Ax - Ax_Cx*By_Ay;
float r = rNumerator / Denominator;
float s = sNumerator / Denominator;
//printf("%f, %f, %f, %f\n", rNumerator, sNumerator, r, s);
if(0<=r && r<=1.0 && 0<=s && s<=1.0){
retVal = r;
}
return retVal;
}
static PyObject *
CCollision_LineIntersection2D(PyObject *self, PyObject *args) {
int res;
float Ax, Ay, Bx, By, Cx, Cy, Dx, Dy;
float returnV;
PyObject* retval;
//从输入参数解析出两个整型数据
res = PyArg_ParseTuple(args, "ffffffff", &Ax, &Ay, &Bx, &By, &Cx, &Cy, &Dx, &Dy);
if (!res) {
return NULL;
}
//调用C函数进行实际操作
returnV = LineIntersection2D(Ax, Ay, Bx, By, Cx, Cy, Dx, Dy);
//将结果转换成一个python对象返回
retval= (PyObject *)Py_BuildValue("f", returnV);
return retval;
}
static PyMethodDef
CCollisionMethods[] = {
{"LineIntersection2D", CCollision_LineIntersection2D, METH_VARARGS},
{NULL, NULL},
};
void initCCollision() {
Py_InitModule("CCollision", CCollisionMethods);
}
setup.py
#!/usr/bin/env python
from distutils.core import setup, Extension
MOD = 'CCollision'
setup(name=MOD, ext_modules=[Extension(MOD, sources=['CCollision.c'])])
编译安装CCollision的命令是:
python setup.py install