• python那些你忽略的性能杀手


    python的性能和计算能力一直被吐槽,从未被超越,越是这样越应该反省平常在使用的过程当中应当注意哪些优化措施,能让我们的程序运行得更快。

    总结一下自己平常在使用 python的过程当中所导致的性能杀死:

    1.内置类型方面:

    python 内部的变量是分为可变类型和不可变类型,这里说的可变与不可变不是说变量与常量的区别,而是关于对象的生命周期问题。

    假设一个python 原生字符串:

    _str = "Hello"
    id(str) = 33738016 #随机值
    _str += "World"
    id(str) = 33738056

    从上面可以看出, id() 值是变了,意味着什么?

    id 值的改变意味着这个对象的内存地址改变,也就是说,执行的 += 操作是将原来的字符串拼接完成后拷贝到新的地址。

    可以看到两次id值相减为40,也就是5个 byte

    所以应该尽量避免过多的 += 操作

    如果需要拼接很多字符串的话尽量使用格式化字符串方式或者使用 str的 join方法

    s = "%s,%s" %(str_1, str_2)
    s = "".join([str_1, str_2])

    总结一下哪些内置类型是变化哪些是不变化的:

    dict, tuple, set 是不变是,字符串,其他变量是变化的

    如果一个dict 或者 set 里面包含字符串或者其他变量,对dict, set的操作不会引起自身变化,但是其引用对象是变化的

    2.一些迭代对象

    在python2.x 版本里面,很多地方会使用到 for e in range(...) 形式或者 for e in E.items() 形式

    这里需要注意的是,在 range()或者 items() 等操作过程中。是会在中间过程生成一个临时的 list

    如果这个list很大的话将会让你的程序陷入噩梦

    解决办法就是在这种for 循环中,使用可迭代对象

    range 可由 xrange 替代,items 可由 iteritems 替代,还有诸如 iterkeys等

    3.类对象

    python的函数调用是很消耗资源的,所以尽量避免过多的函数调用,也可以适当使用lambda表达式替换

    如果某个类需要创建大量的实例,而这个实例在运行过程中不会动态的添加其他的属性,那么可以使用内置的

    __slot__方式

    在类中定义了 __slot__ = ['attr1', 'attr2'] 

    表示这个类只能拥有这些属性,这样避免在类生成过程中会为类自己生成 __dict__属性,这样可以减少很多的资源消耗

    尽量少使用类变量,每个函数完成自己的功能,适当让耦合度降低

    4.循环优化

    多数的计算都发生在循环过程中,所以计算瓶颈可能出现在循环的地方。将循环适当的优化可以做到事半功倍的效果

    while 循环使用 while 1: 而不是 while True:

    使用 while True python也会自动给你转化为 while 1,避免每次循环都要转化一次岂不是更好

    将计算长度移到循环外

    很多同学喜欢这样使用:

    for x in range(0, len( L )):
        do(x)

    这样使用的时候会导致每一次循环都计算一次长度,浪费了很多

    如果要生成的结果是一个list 的话,最好的方式不是使用每次将满足条件的值 append 到这个list

    这样使用可以减少很多资源消耗

    return [ func(e) for e in L ]

      

    5.一些其他的操作

    对于字典的操作,获取一个值最好使用内置 get() 而不是按照下标来使用

    否则需要写成这样:

    try:
        X = d[key]
    except ValueError :
        X = None
     
    或者
     
    if d.has_key(key):
       X =  d[key]
    else:
       X =  None

    这样的代码谁都不喜欢看到  

    在需要使用到 in 操作的地方,使用 set 或者 dict 而不是 list

    这样只需要O(1)时间就可以判断,而 list 会挨个比较

    在可能需要对list 里面的值做排序的地方尽量使用 bisect

    没有看过 bisect 的实现,内部是用的 C模块,估计使用的是红黑树,虽然插入操作需要的时间多一些,但是对于排序号的列表,后期优势就很大了

    在使用到多线程的地方,对一个列表的操作使用 collections.deque()

    collections.deque 支持多线程的原子操作,可以减少你自己加锁解锁的代码复杂性

    在需要读取文件的操作中,使用迭代对象对文件的每一行做操作而不是用 readlines() 或者一次性读取后按行操作

    使用方式做好是这样:

    with open("file", "rb") as fp:
     
         for line in fp:
     
              do(line)

    with 语句2.x版本在文件开头引入  

    from __future__ import with_statement

    能想到的就是这些了,欢迎补充

      

    文章属原创,转载请注明出处 联系作者: Email:zhangbo1@ijinshan.com QQ:513364476
  • 相关阅读:
    poj 3261 Milk Patterns 后缀数组+二分
    poj 2774 Long Long Message(后缀数组入门题)
    hdu 5719 Arrange
    hdu 5720 Wool
    DROP TABLE 恢复
    MySQL数据库改名的三种方法
    MySQL 误操作后数据恢复(update,delete忘加where条件)
    MySQL常用SQL语句优化
    EXPLAIN 命令详解
    mysql sql语句大全
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2770104.html
Copyright © 2020-2023  润新知