python性能优化和源码保护

Python是一门动态解释型语言,由于GIL(全局解释器锁)、GC机制等特性,python运算效率很低。

同时由于python程序没有静态编译的过程,项目代码以py源码的方式交付,任何人都可以获取和修改源代码,无法做到相应的安全保护。

针对这两个问题,可以将Python源代码编译生成C/C++扩展模块的形式(Windows平台生成.pyd文件,Linux生成.so文件),以动态链接库的方式调用。

python调用C/C++扩展函数的时候,GIL会被锁定,直到这个函数结束。由于这期间没有python的字节码被运行,所以线程不会切换,如果在扩展模块中调用阻塞式地I/O函数,python中的多线程机制就形同虚设。

cython

使用cython编译加速python代码,cython是一门编程语言,属于python的超集,也是一个编译器,负责将cython源码(或python源码)翻译成高效的C/C++源码,最终编译成python的扩展模块(.pyd,.so),经过cython翻译编译后,程序执行效率会有明显提升。

Note: 纯python源码被Cython编译后,因为没有使用静态类型定义,性能提升有限,但对for循环,大的列表对象遍历性能有明显优化效果,但多线程GIL的问题同样存在。

使用方法

先用cython将python语言代码转换为c语言代码,然后用c编译器生成可执行文件或动态链接库。

通过shell或python脚本的方式,将项目启动的入口py编译成可执行文件,将其他.py文件编译成.so(__init__.py除外)

单个文件的编译示例

将启动main.py编译成二进制可执行文件main

# 可通过文件头的 #!/usr/bin/env python 标记是否程序启动文件
# step1: 将python代码翻译成c代码(main.c)
cython -D -2 --directive always_allow_keywords=true --embed main.py
# step2: 将c代码编译为目标文件(main.o)
gcc -c -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I/usr/include/python2.7 -o main.o main.c
# step3: 将目标文件编译为二进制可执行文件(main)
gcc -I/usr/include/python2.7 -o main main.o -lpython2.7

将test.py编译为动态链接库test.so

# step1: 将python代码翻译成c代码(test.c)
cython -D -2 --directive always_allow_keywords=true test.py
# step2: 将c代码编译为linux动态链接库文件(test.so)
gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I/usr/include/python2.7 -o test.so test.c

cython参数说明;

cython参数说明:
-D, --no-docstrings, Strip docstrings from the compiled module.

-o, --output-file    Specify name of generated C file
-2                             Compile based on Python-2 syntax and code semantics.
-3                             Compile based on Python-3 syntax and code semantics.

gcc参数说明

-shared:
编译动态库时要用到

-pthread:
在Linux中要用到多线程时,需要链接pthread库

-fPIC:
作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

-fwrapv:
它定义了溢出时候编译器的行为——采用二补码的方式进行操作

-O参数
这是一个程序优化参数,一般用-O2就是,用来优化程序用的
-O2:
会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。 
-O3: 在O2的基础上进行更多的优化

-Wall:
编译时 显示Warning警告,但只会显示编译器认为会出现错误的警告

-fno-strict-aliasing:
“-fstrict-aliasing”表示启用严格别名规则,“-fno-strict-aliasing”表示禁用严格别名规则,当gcc的编译优化参数为“-O2”、“-O3”和“-Os”时,默认会打开“-fstrict-aliasing”。 

-I (大写的i):
是用来指定头文件目录
-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include-->/usr/include-->/usr/local/include 

你可能感兴趣的