python decimal_【进阶】嫌弃Python慢,试试这几个方法?

(给机器学习算法与Python学习加星标,提升AI技能)

选自towardsdatascience,作者:Martin Heinz

本文转自机器之心(nearhuman2014)

本文将介绍如何提升 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 :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 函数是罪魁祸首(惊不惊喜,意不意外),现在我们可以更加专注于计时和性能分析了……计时专用函数现在我们知道了需要关注哪里,那么我们可能只想要给运行缓慢的函数计时而不去管代码的其他部分。我们可以使用一个简单的装饰器来做到这点:
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
接着,将该装饰器按如下方式应用在待测函数上:
@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 库提供了 time.perf_counter 和 time.process_time 两种时间。其区别在于,perf_counter 返回绝对值,其中包括了 Python 程序并不在运行的时间,因此它可能受到机器负载的影响。而 process_time 只返回用户时间(除去了系统时间),也就是只有进程运行时间。让程序更快现在到了真正有趣的部分了,让 Python 程序跑得更快!我不会告诉你一些奇技淫巧或代码段来神奇地解决程序的性能问题,而更多是关于通用的想法和策略。使用这些策略,可以对程序性能产生巨大的影响,有时甚至可以带来高达 30% 的提速。使用内置的数据类型这一点非常明显。内置的数据类型非常快,尤其相比于树或链表等自定义类型而言。这主要是因为内置数据类型使用 C 语言实现,使用 Python 实现的代码在运行速度上和它们没法比。使用 lru_cache 实现缓存/记忆我在之前的博客中介绍过这一技巧,但我认为它值得用一个简单例子再次进行说明:
import functools
import time

# caching up to 12 different results
@functools.lru_cache(maxsize=12)
def slow_func(x):
    time.sleep(2)  # Simulate long computation
    return x

slow_func(1)  # ... waiting for 2 sec before getting result
slow_func(1)  # already cached - result returned instantaneously!

slow_func(3)  # ... waiting for 2 sec before getting result
上面的函数使用 time.sleep 模拟了繁重的计算过程。当我们第一次使用参数 1 调用函数时,它等待了 2 秒钟后返回了结果。当再次调用时,结果已经被缓存起来,所以它跳过了函数体,直接返回结果。使用局部变量这和每个作用域中变量的查找速度有关。我之所以说「每个作用域」,是因为这不仅仅关乎局部变量或全局变量。事实上,就连函数中的局部变量、类级别的属性和全局导入函数这三者的查找速度都会有区别。函数中的局部变量最快,类级别属性(如 self.name)慢一些,全局导入函数(如 time.time)最慢。你可以通过这种看似没有必要的代码组织方式来提高效率:
#  Example #1
class FastClass:

    def do_stuff(self):
        temp = self.value  # this speeds up lookup in loop
        for i in range(10000):
            ...  # Do something with `temp` here

#  Example #2
import random

def fast_function():
    r = random.random
    for i in range(10000):
        print(r())  # calling `r()` here, is faster than global random.random()

使用函数

这也许有些反直觉,因为调用函数会让更多的东西入栈,进而在函数返回时为程序带来负担,但这其实和之前的策略相关。如果你只是把所有代码扔进一个文件而没有把它们放进函数,那么它会因为众多的全局变量而变慢。因此,你可以通过将所有代码封装在 main 函数中并调用它来实现加速,如下所示:
def main():
    ...  # All your previously global code

main()
不要访问属性另一个可能让程序变慢的东西是用来访问对象属性的点运算符(.)。这个运算符会引起程序使用__getattribute__进行字典查找,进而为程序带来不必要的开销。那么,我们怎么避免(或者限制)使用它呢?
#  Slow:
import re

def slow_func():
    for i in range(10000):
        re.findall(regex, line)  # Slow!

#  Fast:
from re import findall

def fast_func():
    for i in range(10000):
        findall(regex, line)  # Faster!
当心字符串当在循环中使用取模运算符(%s)或 .format() 时,字符串操作会变得很慢。有没有更好的选择呢?根据 Raymond Hettinger 近期发布的推文,我们只需要使用 f-string 即可,它可读性更强,代码更加紧凑,并且速度更快!基于这一观点,如下从快到慢列出了你可以使用的一系列方法:
f'{s} {t}'  # Fast!
s + '  ' + t 
' '.join((s, t))
'%s %s' % (s, t) 
'{} {}'.format(s, t)
Template('$s $t').substitute(s=s, t=t)  # Slow!
生成器本质上并不会更快,因为它们的目的是惰性计算,以节省内存而非节省时间。然而,节省的内存会让程序运行更快。为什么呢?如果你有一个大型数据集,并且你没有使用生成器(迭代器),那么数据可能造成 CPU 的 L1 缓存溢出,进而导致访存速度显著变慢。当涉及到效率时,非常重要的一点是 CPU 会将它正在处理的数据保存得离自己越近越好,也就是保存在缓存中。读者可以看一看 Raymond Hettingers 的演讲(https://www.youtube.com/watch?v=OSGv2VnC0go&t=8m17s),其中提到了这些问题。总结优化的第一要义就是「不要去做」。但如果你必须要做,我希望这些小技巧可以帮助到你。然而,优化代码时一定要谨慎,因为该操作可能最终造成代码可读性变差、可维护性变差,这些弊端可能超过代码优化所带来的好处。
参考链接:https://towardsdatascience.com/making-python-programs-blazingly-fast-c1cd79bd1b32

本文为机器之心编译,转载请联系本公众号获得授权。

推荐阅读

惊呆了!这样可以将Numpy加速700倍!

神经网络训不好,看看这37个坑!

InfoSpider | 这个开源爬虫工具箱,一不小心火了!

从AlexNet到BERT:深度学习中那些最重要idea的最简单回顾

32b07af9c958d2adb8de436a41a9c91e.png

b9c2315bdbe65187d642aff0848523e1.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/489887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

王道8套有变化吗_求求你别再套花艺设计公式了

花艺设计也有公式吗&#xff1f;确实有花艺设计只有公式吗&#xff1f;并不是无论是哪门设计学科&#xff0c;公式这种东西&#xff0c;谈多了是否有种千篇一律的感觉&#xff1f;设计风格相似的花艺师要越来越多&#xff0c;一时间竟然以为都是一个人。就和网红一样&#xff0…

对象构造函数的原型图

对象的定义其实很广泛,万物皆为对象,我们创建对象一般都是用构造函数来创建的,这里我们来说说构造函数创建对象的原型图把. 这个问题有点抽象,举个例子来说,方便一点: 这是我们构造函数,这里我们要结合一张 图来说明就更清楚了,这里我们就用一个实例p1好了,其他两个就不用了. 这…

站在AI与神经科学交叉点上的强化学习

来源&#xff1a; 混沌巡洋舰一&#xff0c;强化学习概述让机器来决策&#xff0c;首先体现在如何模仿人类的决策。对于决策这个问题&#xff0c; 对于人类是困难的&#xff0c; 对于机器就更难。而强化学习&#xff0c; 就是一套如何学习决策的方法论。强化学习最初的体现就是…

澜起科技云计算服务器_服务器严重缺货!云应用大爆发!云计算正强势起爆(附龙头)...

催化因素&#xff1a;这两天全国上千万企业、近两亿人开启在家办公模式。阿里、华为、腾讯等各大网络办公平台纷纷告急。对云服务的需求大增也让服务器生产企业开足马力&#xff0c;春节假期里&#xff0c;山东浪潮集团就接到了1500台服务器的订单。目前&#xff0c;多家软件服…

车险赔付率分析报告_车险有变!价格…

各位车友请注意&#xff01;《商业车险综合示范条款(2020版征求意见稿)》于近日发布向社会公开征求意见从修订版条款的内容来看大幅删减了责任免除项目扩展了保险责任在最大化让利于消费者的同时努力提升消费者体验那么&#xff0c;此次修订版有哪些具体的亮点呢&#xff1f;一…

“众声喧哗”中的VR,谁来买单?

来源&#xff1a;VR每日必看未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体系&#xff0c;开展世界人工智能智商评测&#xff1b;开展互联网&…

.npy文件_Numpy库使用入门(六)文件的存取

ERNIE&#xff1a;BERT&#xff0c;你看到我的npy了吗&#xff0c;我记得我放在这个文件夹里的呀(」&#xff1e;&#xff1c;)」BERT&#xff1a;就你还有npy&#xff1f;我还单着呢&#xffe3;へ&#xffe3;ERNIE&#xff1a;你想什么呢&#xff1f;我指的是numpy储存数据的…

redis rua解决库存问题_如何解决高并发下的库存安全问题,没你想得那么复杂(附源码)...

一、 问题不知道大家该开发中有没有遇到这样的一个问题&#xff0c;在电影院购票或者去网上买东西的时候&#xff0c;比方说当年哪吒大电影出来的时候&#xff0c;那抢票相当火爆啊&#xff0c;一票难求&#xff0c;那购票系统的后台是如何保证观众能买到自己喜欢的票同时不用担…

AI 白皮书:赢家、输家

来源&#xff1a;云头条引言&#xff1a;纵观历史&#xff0c;对企业界而言改变游戏规则的始终是技术。制造商取代手艺人&#xff0c;工厂从制造商手里接过接力棒&#xff0c;自动化和遥测技术取代大部分重复性的人力劳动。从个人计算机到互联网和移动商务&#xff0c;在过去的…

python 首次登陆outlook 脚本_记Python“用户环境”的一次完美应用

在之前写过一篇关于虚拟环境使用的文章&#xff0c;但是还没有好好的介绍一下 Python 的用户环境&#xff0c;原因是自己一直没遇到要使用 用户环境 的使用场景&#xff0c;所以就一直懒得写。恰巧这两天&#xff0c;自己遇到了一个使用用户环境的体验可以完爆虚拟环境的案例&a…

今日头条、抖音推荐算法原理全文详解!

来源&#xff1a;运营大叔本次分享将主要介绍今日头条推荐系统概览以及内容分析、用户标签、评估分析&#xff0c;内容安全等原理。一、系统概览推荐系统&#xff0c;如果用形式化的方式去描述实际上是拟合一个用户对内容满意度的函数&#xff0c;这个函数需要输入三个维度的变…

星梦缘陈彦妃_浙江舟山80后女演员,2003年出演偶像剧《星梦缘》,还是专业模特...

陈彦妃&#xff0c;1984年2月4日出生于浙江省舟山市&#xff0c;中国内地影视女演员、流行乐歌手、模特。陈彦妃是一个真性情的女孩&#xff0c;在高中时期拍摄了偶像剧《星梦缘》&#xff0c;在这部戏中&#xff0c;陈彦妃基本上是本色出演&#xff0c;进入大学之后&#xff0…

python hstack_Python小白数据科学教程:NumPy (下)

点击“简说Python”&#xff0c;选择“置顶/星标公众号”福利干货&#xff0c;第一时间送达&#xff01;本文作者&#xff1a;王圣元转载自&#xff1a;王的机器本文偏长(1.8w字)&#xff0c;老表建议先收藏&#xff0c;然后转发朋友圈&#xff0c;然后吃饭、休闲时慢慢看&…

MATLAB并行实现的简单方法

此方法只是利用了matlab的设定&#xff0c;不需要额外知识。 众所周知&#xff0c;matlab是单线程的&#xff0c;但matlab的每个应用窗口都是一个线程&#xff0c;因此可以同时开启多个MATLAB跑程序&#xff0c;占满CPU的所有core。 例如处理多个文件的计算&#xff0c;单线程…

POJ 1631 nlogn求LIS

方法一&#xff1a; 二分 我们可以知道 最长上升子序列的 最后一个数的值是随序列的长度而递增的 &#xff08;呃呃呃 意会意会&#xff09; 然后我们就可以二分找值了&#xff08;并更新&#xff09; //By SiriusRen #include <cstdio> #include <cstring> #incl…

城市大脑与未来超级智能建设规范研究报告即将发布

来源&#xff1a;今日头条21世纪以来&#xff0c;特别是在2010年以来&#xff0c;前沿科技领域出现诸多“大脑”概念&#xff0c;企业界出现谷歌大脑&#xff0c;百度大脑&#xff0c;阿里大脑&#xff0c;360安全大脑&#xff0c;腾讯超级大脑等&#xff0c;产业界出现城市大脑…

练习图200例图纸讲解_【宅家数学课23】经典微课6:苏教版六年级下册比例尺典型例题选讲及练习(含答案)...

(截止日期&#xff1a;3月31日)学习过程1、点击观看经典微课&#xff1a;微课视频《比例尺》2、认真学习典型例题&#xff0c;完成下方练习题3、查看答案&#xff0c;在家长指导下批改&#xff0c;订正错误。苏教版小学数学六年级下册比例尺典型例题选讲及练习【考点分析】【例…

ajax datatype_Ajax的基本使用

Asynchronous javascript and xmlAjax的实现 : 基于一个对象XMLHttpRequest (如何获取?)步骤: 1. 获取ajax对象function getRequestObject() {if (window.XMLHttpRequest) {// 支持Opera, Safari, Mozilla, Chrome,Internet Explorer 7, and IE 8.return(new XMLHttpRequest()…

MATLAB画图详细教程

本文将详细介绍如何用matlab绘图并美化。 关于figure() 创建图窗窗口&#xff1a;figure() figure()的属性&#xff1a; Name&#xff1a;在标题栏显示的名称&#xff0c;接字符串&#xff0c;如Test Position&#xff1a;在电脑屏幕上的位置和大小&#xff0c;后接向量[l…

android 发送广播_从0系统学Android--5.2 发送广播

从0系统学Android--52 发送广播本系列文章目录&#xff1a;更多精品文章分类本系列持续更新中…. 初级阶段内容参考《第一行代码》5.3 发送自定义广播前面已经学习了如何接受广播了&#xff0c;下面来学习如何发送自定义广播&#xff0c;广播类型分为&#xff1a;标准广播和有序…