让你的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 real 0m11,058s user 0m11,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 <frozen importlib._bootstrap_external>: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 <frozen importlib._bootstrap_external>:57(_path_join) 48 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap_external>:59(<listcomp>) 1 0.000 0.000 11.081 11.081 slow_program.py:1(<module>) ... 在这里,我们行使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 (编辑:湖南网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |