前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >让你的Python提速30%!(下)

让你的Python提速30%!(下)

作者头像
AiTechYun
发布2020-02-23 14:32:42
6730
发布2020-02-23 14:32:42
举报
文章被收录于专栏:ATYUN订阅号

编辑 | sunlei 发布 | ATYUN订阅号

前文回顾:让你的Python提速30%!(上)

使它更快

现在进入有趣的部分。让我们帮您的Python程序运行得更快。我(基本上)不会向您展示一些能够神奇地解决性能问题的黑客、技巧和代码片段。这更多的是关于一般的想法和策略,当使用时,它们可以对性能产生巨大的影响,在某些情况下可以提高30%的速度。

使用内置数据类型

这一点很明显。内置数据类型非常快,特别是与我们的自定义类型(如树或链接列表)相比。这主要是因为内置代码是用C实现的,在用Python编写代码时,我们在速度上无法真正匹配。

缓存/记忆lru_cache

用一个简单的例子来重复一下:

代码语言:javascript
复制
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-slower)和全局(例如time.time(最慢))之间也存在差异。

你可以通过使用看起来不必要的(直接的无用的)任务来提高性能,比如:

代码语言:javascript
复制
#  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函数中并调用一次,就可以加快代码的速度,如下所示:

代码语言:javascript
复制
def main():
    ...  # All your previously global code

main()

不访问属性

另一个可能会减慢程序速度的是点运算符(.),它在访问对象属性时使用。此运算符使用_getattribute__触发字典查找,这会在代码中产生额外的开销。那么,我们如何才能真正避免(限制)使用它呢?

代码语言:javascript
复制
#  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!

谨防字符串

在循环中使用例如module(%s)或.format()运行时,对字符串的操作可能会非常慢。我们还有什么更好的选择?根据Raymond Hettinger最近的推文,我们唯一应该使用的是f-string,它是最可读、最简洁、最快的方法。因此,根据这条推文,这是你可以使用的方法列表-从最快到最慢:

代码语言:javascript
复制
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://towardsdatascience.com/making-python-programs-blazingly-fast-c1cd79bd1b32

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ATYUN订阅号 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使它更快
    • 使用内置数据类型
      • 缓存/记忆lru_cache
        • 使用局部变量
          • 使用函数
            • 不访问属性
              • 谨防字符串
              • 结论
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档