用python装饰器来优化算法

     摘要:最近coding时用到了Python装饰器,它的作用太强大了,而且使用也简单,解决了我代码中大量重复计算的瓶颈,下面以计算Fibonacci数列为例来说明问题:

C语言版:

#include <stdio.h>
//fib.c
int fib(int n)
{
	if(n < 3)
	{
		return 1;
	}
	else
	{
		return fib(n-1) + fib(n-2);
	}
}

int main(int argc, char* argv[])
{
	if(argc == 2)
		printf("%d\n", fib(atoi(argv[1])));
	else
		printf("Please enter a parameter\n");
}

编译:gcc -O3 -o fib fib.c

运行:
用时3.28s。

来看下纯Python版的:

#!/usr/bin/env python
#fib.py
import sys

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

if len(sys.argv) == 2:
	print fib(int(sys.argv[1]))
else:
	print "Please enter a parameter"

运行:

用时40.19s,本来是想算45的,无奈迟迟不出结果。

和上面的C版用时相差几百倍多,因为此处计算的是40,当数据越大,则fib的调用呈指数级上升,所以此处预估为几百倍不算夸张,下面会分析此处fib重复调用次数。从这里可以看出Python的确不适合做这种大量重复计算,所以我们就想到了用C/C++来扩展Python,提高计算速度,用Python使用bitey调用C模块中的方法来重写。

Python+ctypes版的:

#!/usr/bin/env python
#fib_ctypes.py

import sys
import ctypes

lib = ctypes.CDLL("./fib.so")
if len(sys.argv) == 2:
	print lib.fib(int(sys.argv[1]))
else:
	print "Please enter a parameter"

运行:

用时9.88s,明显比纯Python版快,但还是和纯C版的相差三倍左右。

再来看下Python+bitey版的:

#!/usr/bin/env python
#fib_bitey.py

import sys
import bitey
import fib

if len(sys.argv) == 2:
	print fib.fib(int(sys.argv[1]))
else:
	print "Please enter a parameter"

运行:

用时6.58s,可以看出比ctypes版的要好点,但比纯C版还是要差些,不过已经很不错了,应该是clang+llvm的功劳。

现在回过头来分析下纯Python版的为什么会这么慢,运行:

发现对fib调用了331160281次,不慢都不正常了,基于Fibonacci数列的特点,我们可以想办法记录上一次计算后的结果,比如计算f(10),可以把计算过的f(9)和f(8)的结果直接返回,而不用递归下去。刚好Python装饰器可以用来记录上次计算的结果,关于Python装饰器的使用请看Python装饰器与面向切面编程

Python装饰器版:

#!/usr/bin/env python
#fib_cache.py
import sys

def cache(fib):
    temp = {}
    def _cache(n):
        if n not in temp:
            temp[n] = fib(n)
        return temp[n]
    return _cache
@cache
def fib(n):
    if n < 2:
        return n
    else:
        return fib(n-2) + fib(n-1)

if len(sys.argv) == 2:
    print fib(int(sys.argv[1]))
else:
    print "Please enter a parameter"

运行:

用时0.02s,比纯C版的都快150多倍!这就是经过装饰器处理后的效果,其实C也能做到缓存结果,但比起Python这种简单明了的方式来说它太复杂了。

      总结:在提升python的处理速度时,我们可以通过boost/ctypes/bitey调用c/c++写的模块,也可以用cython来编译,但最终利用语言自身的特性来优化算法才是王道。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值