提升Python性能,媲美C语言

提升Python性能,媲美C语言,第1张

本篇文章是学习《Python金融大数据分析》第10章“高性能的Python”的笔记~

文章目录
  • 循环
    • numpy
    • numba
    • Cython
  • 递归
    • cython
    • 修饰器

循环

下面以计算平均数为例。


原始代码为:

import random
def average_py(n):
	s=0
	for i in range(n):
		s+=random.random()
	return s/n

若n=10000000,大致运行2s。


numpy

numpy的优势在于其向量化能力。


从形式上看,Python级别的循环消失了,循环在更深的一级上。


平均数可变为:

import random
import numpy as np
def average_np(n):
	s=np.random.random(n)
	return s.mean()

若n=10000000,大致运行224ms。


不过需要注意的是,虽然速度提升了,内存占用也更多。


numba

Numba可以动态编译纯Python代码,在简单情况下,它的应用非常直观。


import numba
average_nb=numba.jit(average_py)

n=10000000
average_nb(n) #第一次运行大概278ms
average_nb(n) #第二次运行81.7ms,第二次运行会明显变快。


以上运行结果显示,第一次运行较慢,第二次及之后运行速度明显加快。


所以对于会重复运行的函数,可以用numba进行编译。


(自己总结,非书中观点)
numba对性能的提升效果很明显,但是值得注意的是,许多情况下 Numba 并不适用,性能增进几乎难以察觉,甚至无法实现。


Cython

Cython=Python+C, 可以静态编译python代码,但是它的应用不想Numba那么简单,通常需要更改代码才能明显加速,即向python代码里面加入一些C语言元素。


由于比较复杂,笔者就没有举例子了,需要更加深入复杂的学习~
但是一般用法是,在代码开头加上

%load_ext Cython
%%cpython

注意:使用之前要先安装Cython第三方包

递归

Python的常规递归函数实现也相对较慢。


递归函数需要多次调用自身,Numba加速效果不明显。


下面以斐波那契数列为例,介绍几种加速方法。


'''
原始函数
'''
def fib_rec_py1(n):
	if n<2:
		return n
	else:
		return fib_rec_py1(n-1)+fib_rec_py1(n-2)

当n=35时,执行时间约为3.74s。


若用numba,运行时间大约为3.54s。


cython
'''
cython加速
'''
%%cython
def fib_rec_cy(int n):
	if n<2:
		return n
	else:
		return fib_rec_cy(n-1)+fib_rec_cy(n-2)

当n=35时,执行时间约为936ms。


修饰器

递归算法的主要问题是中间结果不会缓存,而是重新计算。


为了避免出现这种特有的问题,可以使用一个装饰器(decorator)来负责缓存中间结果。


它可以将执行速度提高好几个数量级。


'''
修饰器
'''
from functools import lru_cache as cache 
@cache(maxsize=None)
def fib_rec_py2(n):
	if n<2:
		return n
	else:
		return fib_rec_py2(n-1)+fib_rec_py2(n-2)

当n=35时,执行时间约为98us,几乎瞬间出结果。



递归的效率很低,如果可以,尽量不使用递归。


比如斐波那契数列可以用以下方式计算:

def fib_it_py(n):
	x,y=0,1
	for i in range(1,n+1):
		x,y=y,x+y
	return x

当n=80时,运行时间大约为26us,如果用上Numba,cython,会更加迅速

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/569858.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存