title: 加速python执行 date: 2017-09-16 16:00:00 tags: quant


和C++, java等语言相比,python的执行速度一直是诟病。但是python的易用性,广泛的包扩展等却是它的强项。做quant最重要的就是做出策略,我希望99%的时间都花在策略上,临门一脚的1%放在优化代码性能上。

有什么方法能提高性能,节约运算时间,最好是随手就能提高个几十倍速度。

测试基准

很多团队对比不同语言或者技术之间的运算速度,都采用了Fibonacci 函数这样一段简单编码作为测试。

def fib(n):
if n<2:
return n
return fib(n-1)+fib(n-2)

%timeit fib(20)

结果是

100 loops, best of 3: 2.77 ms per loop

这意味著计时器执行了以下操作:

1.运行 fib(20) 100 次,存储总运行时间
2.运行 fib(20) 100 次,存储总运行时间
3.运行 fib(20) 100 次,存储总运行时间
从 3 次运行中获取最小的运行时间,将它除以 100,然后输出结果,该结果就是 fib(20) 的最佳运行时间

记住执行一次需要2.77毫秒,把它作为我们的测试基准。

方案一 Numba 的JIT技术

JIT(just-in-time compilation)是动态编译的一种形式,是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态直译。静态编译的程序在执行前全部被翻译为机器码,而直译边运行边翻译。即时编译器则混合了这二者,一句一句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。

import numba @numba.jit 作为装饰器对于函数进行局部优化加速 对于高维数组性价比更高, 因为numba载入需要时间。

import numba
@numba.jit
def fib(n):
if n<2:
return n
return fib(n-1)+fib(n-2)

结果是

10000 loops, best of 3: 76.1 μs per loop

最快一次执行时76.1微妙。

方案二 Cython

2.1 Cython动态编译

在ipython或者jupyter里 先载入Cython到notebook里

%load_ext Cython

%%cython
def fib(n):
if n<2:
return n
return fib(n-1)+fib(n-2)

%timeit fib(20)

结果:

1000 loops, best of 3: 1.2 ms per loop

最好的一次是1.2毫秒。

2.2 Cython静态类型声明

尝试使用静态类型。使用关键字cpdef代替def来声明函数,同时声明函数参数类型和返回值类型。使用Cython报错,文章底部有解决办法。

%%cython
cpdef long fib(long n):
if n<2:
return n
return fib(n-1)+fib(n-2)

结果是

10000 loops, best of 3: 38.6 μs per loop

在文件编译可以这样使用:

  1. 代码放到.pyx文件里
  2. 运行python setup.py build_ext --inplace,执行编译 若编译成功则在当前文件夹下会出现test.pyd, 像使用其他模块一样载入(import)test.pyd使用 Cython编译,详见 jianshu.com/p/0dffe9aeb

我们总结下以上几种方案的速度优势:

方案消耗时间基准2.8 msNumba.JIT76.1 μsCython动态编译1.2 msCython静态类型声明38.6 μs

使用Cython静态类型声明和Numba.JIT的代码比基准执行速度大大提升,分别是30倍,70倍。使用过程也非常简单,仅仅是添加了装饰器,类型声明。对于频繁调用自定义运算符函数,随手速度就可以提升几十倍甚至上百倍。

使用Cython报错

Unable find vcvarsall.bat, 该如何解决?

Step 1. 打开附件的运行,输入regedit,打开注册表编辑器

Step 2. 配置

如果你安装的Python是32位的,则连续创建如下项: HKEY_CURRENT_USERSoftwareMicrosoftVisualStudio9.0SetupVC

如果你安装的Python是64位的,则连续创建如下项: HKEY_CURRENT_USERSoftwareWow6432NodeMicrosoftVisualStudio9.0SetupVC

Step 3. 并在此项下新建字元串值:

名称:productdir

数据:vcvarsall.bat所在路径

注意:路径中不包含最后的反斜杠。

比如我的vcvarsall.bat文件所在路径

C:UsersHansAppDataLocalProgramsCommonMicrosoftVisual C++ for Python9.0

Ref:

  1. ibm.com/developerworks/
  2. blog.csdn.net/donger_so

推荐阅读:

相关文章