热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python中if的效率_Python性能优化的20条建议

1、优化算法时间复杂度算法的时间复杂度对程序的执行效率影响最大,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找某一个元素的时间复

1、优化算法时间复杂度

算法的时间复杂度对程序的执行效率影响最大,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找某一个元素的时间复杂度分别是O(n)和O(1)。不同的场景有不同的优化方式,总得来说,一般有分治,分支界限,贪心,动态规划等思想。

2、减少冗余数据

如用上三角或下三角的方式去保存一个大的对称矩阵。在0元素占大多数的矩阵里使用稀疏矩阵表示。

3、合理使用copy与deepcopy

对于dict和list等数据结构的对象,直接赋值使用的是引用的方式,而有些情况下需要复制整个对象,这时可以使用copy包里的copy和deepcopy,这两个函数的不同之处在于后者是递归复制的。效率也不一样:(以下程序在ipython中运行)

import copy

a = range(100000)

%timeit -n 10 copy.copy(a) # 运行10次 copy.copy(a)

%timeit -n 10 copy.deepcopy(a)

10 loops, best of 3: 1.55 ms per loop

10 loops, best of 3: 151 ms per loop

timeit后面的-n表示运行的次数,后两行对应的是两个timeit的输出,下同。由此可见后者慢一个数量级。

4、使用dict或set查找元素

python dict和set都是使用hash表来实现(类似c++11标准库中unordered_map),查找元素的时间复杂度是O(1)

a = range(1000)

s = set(a)

d = dict((i,1) for i in a)

%timeit -n 10000 100 in d

%timeit -n 10000 100 in s

10000 loops, best of 3: 43.5 ns per loop

10000 loops, best of 3: 49.6 ns per loop

dict的效率略高(占用的空间也多一些)。

5、合理使用生成器(generator)和yield

%timeit -n 100 a = (i for i in range(100000))

%timeit -n 100 b = [i for i in range(100000)]

100 loops, best of 3: 1.54 ms per loop

100 loops, best of 3: 4.56 ms per loop

使用()得到的是一个generator对象,所需要的内存空间与列表的大小无关,所以效率会高一些。在具体应用上,比如set(i for i in range(100000))会比set([i for i in range(100000)])快。但是对于需要循环遍历的情况:

%timeit -n 10 for x in (i for i in range(100000)): pass

%timeit -n 10 for x in [i for i in range(100000)]: pass

10 loops, best of 3: 6.51 ms per loop

10 loops, best of 3: 5.54 ms per loop

后者的效率反而更高,但是如果循环里有break,用generator的好处是显而易见的。yield也是用于创建generator:

def yield_func(ls):

for i in ls:

yield i+1

def not_yield_func(ls):

return [i+1 for i in ls]

ls = range(1000000)

%timeit -n 10 for i in yield_func(ls):pass

%timeit -n 10 for i in not_yield_func(ls):pass

10 loops, best of 3: 63.8 ms per loop

10 loops, best of 3: 62.9 ms per loop

对于内存不是非常大的list,可以直接返回一个list,但是可读性yield更佳人个喜好python2.x内置generator功能的有xrange函数、itertools包等。

6、优化循环

循环之外能做的事不要放在循环内,比如下面的优化可以快一倍:

a = range(10000)

size_a = len(a)

%timeit -n 1000 for i in a: k = len(a)

%timeit -n 1000 for i in a: k = size_a

1000 loops, best of 3: 569 ?s per loop

1000 loops, best of 3: 256 ?s per loop

7、优化包含多个判断表达式的顺序

对于and,应该把满足条件少的放在前面,对于or,把满足条件多的放在前面。如:

a = range(2000)

%timeit -n 100 [i for i in a if 10

%timeit -n 100 [i for i in a if 1000

%timeit -n 100 [i for i in a if i % 2 == 0 and i > 1900]

%timeit -n 100 [i for i in a if i > 1900 and i % 2 == 0]

100 loops, best of 3: 287 ?s per loop

100 loops, best of 3: 214 ?s per loop

100 loops, best of 3: 128 ?s per loop

100 loops, best of 3: 56.1 ?s per loop

8、使用join合并迭代器中的字符串

In [1]: %%timeit

...: s = ''

...: for i in a:

...: s += i

...:

10000 loops, best of 3: 59.8 ?s per loop

In [2]: %%timeit

s = ''.join(a)

...:

100000 loops, best of 3: 11.8 ?s per loop

join对于累加的方式,有大约5倍的提升。

9、选择合适的格式化字符方式

s1, s2 = 'ax', 'bx'

%timeit -n 100000 'abc%s%s' % (s1, s2)

%timeit -n 100000 'abc{0}{1}'.format(s1, s2)

%timeit -n 100000 'abc' + s1 + s2

100000 loops, best of 3: 183 ns per loop

100000 loops, best of 3: 169 ns per loop

100000 loops, best of 3: 103 ns per loop

三种情况中,%的方式是最慢的,但是三者的差距并不大(都非常快)。(个人觉得%的可读性最好)

10、不借助中间变量交换两个变量的值

In [3]: %%timeit -n 10000

a,b=1,2

....: c=a;a=b;b=c;

....:

10000 loops, best of 3: 172 ns per loop

In [4]: %%timeit -n 10000

a,b=1,2

a,b=b,a

....:

10000 loops, best of 3: 86 ns per loop

使用a,b=b,a而不是c=a;a=b;b=c;来交换a,b的值,可以快1倍以上。

11、使用if is

a = range(10000)

%timeit -n 100 [i for i in a if i == True]

%timeit -n 100 [i for i in a if i is True]

100 loops, best of 3: 531 ?s per loop

100 loops, best of 3: 362 ?s per loop

使用 if is True 比 if == True 将近快一倍。

12、使用级联比较x

x, y, z = 1,2,3

%timeit -n 1000000 if x

%timeit -n 1000000 if x

1000000 loops, best of 3: 101 ns per loop

1000000 loops, best of 3: 121 ns per loop

x

13、while 1 比 while True 更快

def while_1():

n = 100000

while 1:

n -= 1

if n <&#61; 0: break

def while_true():

n &#61; 100000

while True:

n -&#61; 1

if n <&#61; 0: break

m, n &#61; 1000000, 1000000

%timeit -n 100 while_1()

%timeit -n 100 while_true()

100 loops, best of 3: 3.69 ms per loop

100 loops, best of 3: 5.61 ms per loop

while 1 比 while true快很多&#xff0c;原因是在python2.x中&#xff0c;True是一个全局变量&#xff0c;而非关键字。

14、使用**而不是pow

%timeit -n 10000 c &#61; pow(2,20)

%timeit -n 10000 c &#61; 2**20

10000 loops, best of 3: 284 ns per loop

10000 loops, best of 3: 16.9 ns per loop

**就是快10倍以上&#xff01;

15、使用 cProfile, cStringIO 和 cPickle等用c实现相同功能&#xff08;分别对应profile, StringIO, pickle&#xff09;的包

import cPickle

import pickle

a &#61; range(10000)

%timeit -n 100 x &#61; cPickle.dumps(a)

%timeit -n 100 x &#61; pickle.dumps(a)

100 loops, best of 3: 1.58 ms per loop

100 loops, best of 3: 17 ms per loop

由c实现的包&#xff0c;速度快10倍以上&#xff01;

16、使用最佳的反序列化方式

下面比较了eval, cPickle, json方式三种对相应字符串反序列化的效率&#xff1a;

import json

import cPickle

a &#61; range(10000)

s1 &#61; str(a)

s2 &#61; cPickle.dumps(a)

s3 &#61; json.dumps(a)

%timeit -n 100 x &#61; eval(s1)

%timeit -n 100 x &#61; cPickle.loads(s2)

%timeit -n 100 x &#61; json.loads(s3)

100 loops, best of 3: 16.8 ms per loop

100 loops, best of 3: 2.02 ms per loop

100 loops, best of 3: 798 ?s per loop

可见json比cPickle快近3倍&#xff0c;比eval快20多倍。

17、使用C扩展(Extension)

目前主要有CPython(python最常见的实现的方式)原生API, ctypes,Cython&#xff0c;cffi三种方式&#xff0c;它们的作用是使得Python程序可以调用由C编译成的动态链接库&#xff0c;其特点分别是&#xff1a;

CPython原生API: 通过引入Python.h头文件&#xff0c;对应的C程序中可以直接使用Python的数据结构。实现过程相对繁琐&#xff0c;但是有比较大的适用范围。

ctypes: 通常用于封装(wrap)C程序&#xff0c;让纯Python程序调用动态链接库&#xff08;Windows中的dll或Unix中的so文件&#xff09;中的函数。如果想要在python中使用已经有C类库&#xff0c;使用ctypes是很好的选择&#xff0c;有一些基准测试下&#xff0c;python2&#43;ctypes是性能最好的方式。

Cython: Cython是CPython的超集&#xff0c;用于简化编写C扩展的过程,Cython的优点是语法简洁&#xff0c;可以很好地兼容numpy等包含大量C扩展的库。Cython的使得场景一般是针对项目中某个算法或过程的优化。在某些测试中&#xff0c;可以有几百倍的性能提升。

cffi: cffi的就是ctypes在pypy&#xff08;详见下文&#xff09;中的实现&#xff0c;同进也兼容CPython。cffi提供了在python使用C类库的方式&#xff0c;可以直接在python代码中编写C代码&#xff0c;同时支持链接到已有的C类库。

使用这些优化方式一般是针对已有项目性能瓶颈模块的优化&#xff0c;可以在少量改动原有项目的情况下大幅度地提高整个程序的运行效率。

18、并行编程

因为GIL的存在&#xff0c;Python很难充分利用多核CPU的优势。但是&#xff0c;可以通过内置的模块multiprocessing实现下面几种并行模式&#xff1a;

多进程&#xff1a;对于CPU密集型的程序&#xff0c;可以使用multiprocessing的Process,Pool等封装好的类&#xff0c;通过多进程的方式实现并行计算。但是因为进程中的通信成本比较大&#xff0c;对于进程之间需要大量数据交互的程序效率未必有大的提高。

多线程&#xff1a;对于IO密集型的程序&#xff0c;multiprocessing.dummy模块使用multiprocessing的接口封装threading&#xff0c;使得多线程编程也变得非常轻松(比如可以使用Pool的map接口&#xff0c;简洁高效)。

分布式&#xff1a;multiprocessing中的Managers类提供了可以在不同进程之共享数据的方式&#xff0c;可以在此基础上开发出分布式的程序。

不同的业务场景可以选择其中的一种或几种的组合实现程序性能的优化。

19、终级大杀器&#xff1a;PyPy

PyPy是用RPython(CPython的子集)实现的Python&#xff0c;根据官网的基准测试数据&#xff0c;它比CPython实现的Python要快6倍以上。快的原因是使用了Just-in-Time(JIT)编译器&#xff0c;即动态编译器&#xff0c;与静态编译器(如gcc,javac等)不同&#xff0c;它是利用程序运行的过程的数据进行优化。由于历史原因目前pypy中还保留着GIL不过正在进行的STM项目试图将PyPy变成没有GIL的Python。如果python程序中含有C扩展(非cffi的方式)&#xff0c;JIT的优化效果会大打折扣&#xff0c;甚至比CPython慢&#xff08;比Numpy&#xff09;所以在PyPy中最好用纯Python或使用cffi扩展。随着STM,Numpy等项目的完善&#xff0c;相信PyPy将会替代CPython。

20、使用性能分析工具

除了上面在ipython使用到的timeit模块,还有cProfilecProfile的使用方式也非常简单:python -m cProfile filename.py&#xff0c; 是要运行程序的文件名&#xff0c;可以在标准输出中看到每一个函数被调用的次数和运行的时间&#xff0c;从而找到程序的性能瓶颈&#xff0c;然后可以有针对性地优化。

图片未显示&#xff0c;点击后可以关注公众号”四川CDA数据分析师“。



推荐阅读
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • 本文回顾了作者初次接触Unicode编码时的经历,并详细探讨了ASCII、ANSI、GB2312、UNICODE以及UTF-8和UTF-16编码的区别和应用场景。通过实例分析,帮助读者更好地理解和使用这些编码。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 在C#编程中,数值结果的格式化展示是提高代码可读性和用户体验的重要手段。本文探讨了多种格式化方法和技巧,如使用格式说明符、自定义格式字符串等,以实现对数值结果的精确控制。通过实例演示,展示了如何灵活运用这些技术来满足不同的展示需求。 ... [详细]
  • 本文详细介绍了批处理技术的基本概念及其在实际应用中的重要性。首先,对简单的批处理内部命令进行了概述,重点讲解了Echo命令的功能,包括如何打开或关闭回显功能以及显示消息。如果没有指定任何参数,Echo命令会显示当前的回显设置。此外,文章还探讨了批处理技术在自动化任务执行、系统管理等领域的广泛应用,为读者提供了丰富的实践案例和技术指导。 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 应用链时代,详解 Avalanche 与 Cosmos 的差异 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 在机器学习领域,深入探讨了概率论与数理统计的基础知识,特别是这些理论在数据挖掘中的应用。文章重点分析了偏差(Bias)与方差(Variance)之间的平衡问题,强调了方差反映了不同训练模型之间的差异,例如在K折交叉验证中,不同模型之间的性能差异显著。此外,还讨论了如何通过优化模型选择和参数调整来有效控制这一平衡,以提高模型的泛化能力。 ... [详细]
  • Python 序列图分割与可视化编程入门教程
    本文介绍了如何使用 Python 进行序列图的快速分割与可视化。通过一个实际案例,详细展示了从需求分析到代码实现的全过程。具体包括如何读取序列图数据、应用分割算法以及利用可视化库生成直观的图表,帮助非编程背景的用户也能轻松上手。 ... [详细]
  • 本文详细探讨了Oracle数据库中Number和Float数据类型的特性和使用方法。通过对比分析,解释了Number类型在精度和范围上的优势,以及Float类型在处理科学计算时的灵活性。文章还介绍了Number数据类型的语法结构及其在实际应用中的最佳实践,帮助读者更好地理解和选择合适的数据类型以满足不同的业务需求。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
author-avatar
手机用户2502903213
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有