热门标签 | 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数据分析师“。



推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 作用域链迷惑性代码vara100;functiontest(){console.log(a);}functiontestFun(){vara200;test();}不假思索的想到出 ... [详细]
  • 详解 Python 的二元算术运算,为什么说减法只是语法糖?[Python常见问题]
    原题|UnravellingbinaryarithmeticoperationsinPython作者|BrettCannon译者|豌豆花下猫(“Python猫 ... [详细]
  • KVC:Key-valuecodingisamechanismforindirectlyaccessinganobject’sattributesandrelations ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 获取时间的函数js代码,js获取时区代码
    本文目录一览:1、js获取服务器时间(动态)2 ... [详细]
  • Imdevelopinganappwhichneedstogetmusicfilebystreamingforplayinglive.我正在开发一个应用程序,需要通过流 ... [详细]
  • fileuploadJS@sectionscripts{<scriptsrc~Contentjsfileuploadvendorjquery.ui.widget.js ... [详细]
  • 前言:原本纠结于Web模板,选了Handlebars。后来发现页面都是弱逻辑的,不支持复杂逻辑表达式。几乎要放弃之际,想起了Javascript中ev ... [详细]
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社区 版权所有