python画笔提速_让你的Python提速30%!(上)

讨厌Python的人总是说,他们不想使用Python的原因之一是它的速度太慢。好吧,不管使用哪种编程语言,具体的程序是快还是慢,很大程度上取决于编写程序的开发人员以及他们编写优化的快速程序的技能和能力。

所以,让我们来证明一些人是错的,让我们看看如何提高Python程序的性能并使它们变得非常快!

时间和剖析

在开始优化任何东西之前,我们首先需要找出代码的哪些部分实际上会减慢整个程序的速度。有时,程序的瓶颈可能很明显,但如果您不知道它在哪里,那么下面是您可以找到的选项:

注:这是我将用于演示目的的程序,它计算e的X次方(取自Python文档):

# slow_program.py

from decimal import *

def exp(x):

getcontext().prec += 2

i, lasts, s, fact, num = 0, 0, 1, 1, 1

while s != lasts:

lasts = s

i += 1

fact *= i

num *= x

s += num / fact

getcontext().prec -= 2

return +s

exp(Decimal(150))

exp(Decimal(400))

exp(Decimal(3000))

最懒的“剖析”

首先,最简单、最懒的解决方案-Unix time命令:

~ $ time python3.8 slow_program.py

real0m11,058s

user0m11,050s

sys 0m0,008s

如果你只想给你的整个程序计时,这是可行的,但这通常是不够的…

最详细的剖析

在光谱的另一端是cProfile,它会给你提供太多的信息:

~ $ python3.8 -m cProfile -s time slow_program.py

1297 function calls (1272 primitive calls) in 11.081 seconds

Ordered by: internal time

ncalls tottime percall cumtime percall filename:lineno(function)

3 11.079 3.693 11.079 3.693 slow_program.py:4(exp)

1 0.000 0.000 0.002 0.002 {built-in method _imp.create_dynamic}

4/1 0.000 0.000 11.081 11.081 {built-in method builtins.exec}

6 0.000 0.000 0.000 0.000 {built-in method __new__ of type object at 0x9d12c0}

6 0.000 0.000 0.000 0.000 abc.py:132(__new__)

23 0.000 0.000 0.000 0.000 _weakrefset.py:36(__init__)

245 0.000 0.000 0.000 0.000 {built-in method builtins.getattr}

2 0.000 0.000 0.000 0.000 {built-in method marshal.loads}

10 0.000 0.000 0.000 0.000 :1233(find_spec)

8/4 0.000 0.000 0.000 0.000 abc.py:196(__subclasscheck__)

15 0.000 0.000 0.000 0.000 {built-in method posix.stat}

6 0.000 0.000 0.000 0.000 {built-in method builtins.__build_class__}

1 0.000 0.000 0.000 0.000 __init__.py:357(namedtuple)

48 0.000 0.000 0.000 0.000 :57(_path_join)

48 0.000 0.000 0.000 0.000 :59()

1 0.000 0.000 11.081 11.081 slow_program.py:1()

...

在这里,我们使用cProfile模块和time参数运行测试脚本,以便按内部时间(cumtime)对行进行排序。这给了我们很多信息,你可以看到上面的行大约是实际输出的10%。从这里,我们可以看出exp函数是罪魁祸首(惊喜,惊喜),现在我们可以得到更具体的时间和分析…

时间特定功能

现在我们知道了应该将注意力放在哪里,我们可能希望对慢速函数计时,而不需要测量代码的其余部分。为此,我们可以使用简单的decorator:

def timeit_wrapper(func):

@wraps(func)

def wrapper(*args, **kwargs):

start = time.perf_counter() # Alternatively, you can use time.process_time()

func_return_val = func(*args, **kwargs)

end = time.perf_counter()

print('{0:<10}.{1:<8} : {2:<8}'.format(func.__module__, func.__name__, end - start))

return func_return_val

return wrapper

这个decorator随后可以应用于测试中的函数,如下所示:

@timeit_wrapper

def exp(x):

...

print('{0:<10} {1:<8} {2:^8}'.format('module', 'function', 'time'))

exp(Decimal(150))

exp(Decimal(400))

exp(Decimal(3000))

这会给我们这样的输出:

~ $ python3.8 slow_program.py

module function time

__main__ .exp : 0.003267502994276583

__main__ .exp : 0.038535295985639095

__main__ .exp : 11.728486061969306

要考虑的一件事是我们实际(想要)测量的是什么样的时间。时间包提供Time.perf_计数器和Time.process_时间。这里的区别在于perf_计数器返回绝对值,其中包括Python程序进程未运行的时间,因此它可能会受到机器负载的影响。另一方面,process_time只返回用户时间(不包括系统时间),这只是进程的时间。

原文链接:https://towardsdatascience.com/making-python-programs-blazingly-fast-c1cd79bd1b32

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值