笔记-Python-性能优化
笔记-Python-性能优化
1. 开始
1.1. python性能差么?
做一个判断前,先问是不是。
python运行效率低是事实。
1.2. 为什么?
原因:
- Python是动态语言,
一个变量所指向的对象在运行时才能确定,编译器做不了预测,也就无从优化;与此相对的是在静态语言中,编译时就确定了运行时的代码。
- python是解释执行,但不支持jit
- python中一切都是对象,每个对象都需要维护引用计数,增加了额外的工作;
- GIL,不解释
- 垃圾回收
这个可能是所有具有垃圾回收的编程语言的通病。python采用标记和分代的垃圾回收策略,每次垃圾回收的时候都会中断正在执行的程序,造成所谓的顿卡。infoq上有一篇文章,提到禁用Python的GC机制后,Instagram性能提升了10%。
1.3. 总结
效率的实质是资源的有效利用率,在代码运行中可理解为处理能力消耗、内存消耗;
但面向整个开发项目而言还有一个效率是开发效率,这是对于程序员而言的,两者相加才是整个项目的效率;
对于一个单流程的简单任务而言,效率基本上是100%,因为没有任何可以优化的地方;
对于有着复杂流程,多对象的任务,有两种方式来实现:
- 针对每一个对象,每一个处理过程设计代码,无疑运行效率会非常高,但开发效率会降低,典型的就是C++,C,更高效一点的就是汇编了;
- 封装,提高通用性,毫无疑问会增加内存,管理开销,典型就是面向对象编程;
事物都有多面性,专精效率高,但通用性,可扩展性就不尽人意了;可扩展性高了,一般对于某些专项任务而言,运行效率就难以保证了;
对于不同语言的特性,要视具体项目情况而用,择其长处而用之;
语言集成化应该是一种趋势,就像汇编到C,C++,.NET,JAVA,很多场景下并不是极端注重性能,开发效率反而成为了项目的短板,那么使用胶水语言就是合理选择了。
2. 优化方法
上文都在说python运行效率低,那么有没有方法来提高它的运行效率,同时还保证一定的开发效率呢,下面将介绍一些常用提高python运行效率的方法;
从上有这么几种优化方法:
- 代码风格:避免写低运行效率的代码;
- 优化编译:使用支持JIT的编译器或更高效的编译器
- C扩展:对于有需求的核心部分使用C扩展
2.1. 代码风格
- 使用迭代器iterator,for example:
dict的iteritems 而不是items(同itervalues,iterkeys)
使用generator,特别是在循环中可能提前break的情况
- 判使用if is使用 if is True 比 if == True 将近快一倍。
- 判断一个对象是否在一个集合中,使用set而不是list
- 对于大量字符串的累加,使用join操作
- 使用for else(while else)语法
- 不借助中间变量交换两个变量的值: a, b = b, a
- 使用代复杂度的算法
- 循环优化:能只执行一次的不要放到循环中反复执行;
- 优化包含多个判断表达式的顺序
对于and,应该把满足条件少的放在前面,对于or,把满足条件多的放在前面
- while 1 比 while True 更快。
2.2. 编译环境
PyPy是用RPython(CPython的子集)实现的Python,根据官网的基准测试数据,它比CPython实现的Python要快6倍以上。快的原因是使用了Just-in-Time(JIT)编译器,即动态编译器,与静态编译器(如gcc,javac等)不同,它是利用程序运行的过程的数据进行优化。
如果python程序中含有C扩展(非cffi的方式),JIT的优化效果会大打折扣,甚至比CPython慢(比Numpy)。所以在PyPy中最好用纯Python或使用cffi扩展。
2.3. C扩展
有时已经找到了性能热点,但这个热点就是要运行大量的计算,而且没法cache,没法省略。。。这个时候就该python的C扩展出马了,C扩展就是把部分python代码用C或者C++重新实现,然后编译成动态链接库,提供接口给其它python代码调用。由于C语言的效率远远高于python代码,所以使用C扩展是非常普遍的做法,python的很多对性能有要求的库都使用或者提供了C扩展。
3. 性能分析工具-
Python中最常用的性能分析工具主要有:cProfiler, line_profiler以及memory_profiler等。他们以不同的方式帮助我们分析Python代码的性能。这里主要关注Python内置的cProfiler,并使用它帮助我们分析并优化程序
4. 附录
4.1. JIT
JIT编译器,英文写作Just-In-Time Compiler,中文意思是即时编译器。
JIT是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态解释。静态编译的程序在执行前全部被翻译为机器码,而解释执行的则是一句一句边运行边翻译。
在Java编程语言和环境中,即时编译器(JIT compiler,just-in-time compiler)是一个把Java的字节码(包括需要被解释的指令的程序)转换成可以直接发送给处理器的指令的程序。当你写好一个Java程序后,源语言的语句将由Java编译器编译成字节码,而不是编译成与某个特定的处理器硬件平台对应的指令代码(比如,Intel的Pentium微处理器或IBM的System/390处理器)。字节码是可以发送给任何平台并且能在那个平台上运行的独立于平台的代码。
4.2. python与JIT
Pypy从表面意思上面来说的话,就是用Python实现的Python。但是更准确的描述应该是RPython实现的Python。
RPython是Python的子集,为什么到现在CPython一直没有加入JIT功能,就是因为它的变量的类型是运行时确定的,也正是因为这样,JIT很难做。
x = random.choice([1, "foo"])
在编译期,很难确定这是x是什么类型的,所以JIT优化很难做,这个时候就使用了RPython来实现Python的语法了,但是它具有静态类型,这样JIT实现起来更加容易。
RPython实现的是Python代码的解析器,所以它只是一个编译器的前端,那么编译器的后端是什么呢?目前Pypy只实现了Python到C的编译,也就是说编译器的后端实现了直接转成了机器码。
当然,编译器后端也可以编译成Java字节码,C#字节码。这个只是暂时没有实现而已。
Pypy之所以难以理解,就是因为很多程序员并没有学习过编译原理,简单介绍下,
1.编译前期,就相当于词法分析器,把源代码分析成中间格式,这种格式是不能执行的,需要进入第2个步骤
2.编译后期生成的文件就相当于字节码,生成了Java字节码就能在JVM上面执行,生成了.Net字节码就能在CLR虚拟机上面运行
Pypy和上面做一下对比就清楚了。
1.RPython的功能就是实现词法的分析
2.Pypy会根据RPython生成的中间文件,进行后期编译,因为RPython具有的静态类型,实现JIT更简单,这也是为什么使用RPython的原因。
笔记-Python-性能优化的更多相关文章
- Android App性能优化笔记之一:性能优化是什么及为什么?
By Long Luo 周星驰的电影<功夫>里面借火云邪神之口说出了一句至理名言:“天下武功,唯快不破”. 在移动互联网时代,同样如此,留给一个公司的窗口往往只有很短的时间,如何把握住 ...
- Python性能优化(转)
分成两部分:代码优化和工具优化 原文:http://my.oschina.net/xianggao/blog/102600 阅读 Zen of Python,在Python解析器中输入 import ...
- Python性能优化方案
Python性能优化方案 从编码方面入手,代码算法优化,如多重条件判断有限判断先决条件(可看 <改进python的91个建议>) 使用Cython (核心算法, 对性能要求较大的建议使用C ...
- python性能优化
注意:本文除非特殊指明,”python“都是代表CPython,即C语言实现的标准python,且本文所讨论的是版本为2.7的CPython. python为什么性能差: 当我们提到一门编程语言的 ...
- Python性能优化:PyPy、Numba 与 Cython。PyPy的安装及对应pip的安装
性能优化讨论见参考1:大概意思是,PyPy内置JIT,对纯Python项目兼容性极好,几乎可以直接运行并直接获得性能提升:缺点是对很多C语言库支持性不好.Numba是一个库,可以在运行时将Python ...
- Python性能优化的20条建议 (转载)
优化算法时间复杂度 算法的时间复杂度对程序的执行效率影响最大,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找某一个元素的时间复杂度分别是O(n)和O(1).不同的场 ...
- python 性能优化
1.优化循环 循环之外能做的事不要放在循环内,比如下面的优化可以快一倍 2.使用join合并迭代器中的字符串 join对于累加的方式,有大约5倍的提升 3.使用if is 使用if is True比i ...
- python基础===Python性能优化的20条建议
优化算法时间复杂度 算法的时间复杂度对程序的执行效率影响最大,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找某一个元素的时间复杂度分别是O(n)和O(1).不同的场 ...
- python性能优化建议
参考: https://segmentfault.com/a/1190000000666603 http://blog.csdn.net/zhoudaxia/article/details/23853 ...
- Python性能优化的20条建议
优化算法时间复杂度 算法的时间复杂度对程序的执行效率影响最大,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找某一个元素的时间复杂度分别是O(n)和O(1).不同的场 ...
随机推荐
- github,gitlab的区别
链接:https://blog.csdn.net/Xiamen_XiaoHong/article/details/83655447 总而言之:gitlab最优
- python 网页中文显示Unicode码
print repr(a).decode("unicode–escape") 注:a是要输出的结果,
- 前端——语言——Core JS——《The good part》读书笔记——第九,十章节(Style,Good Features)
第九章节 本章节不再介绍知识点,而是作者在提倡大家培养良好的编码习惯,使用Good parts of JS,避免Bad parts of JS.它是一篇文章. 本文的1-3段阐述应用在开发过程中总会遇 ...
- Petr and a Combination Lock
Petr has just bought a new car. He's just arrived at the most known Petersburg's petrol station to r ...
- Python 之路
Python之路[第一篇]:Python简介和入门 Python之路[第二篇]:Python基础(一) Python之路[第三篇]:Python基础(二) Python之路[第四篇]:模块 Pytho ...
- JS中constructor属性
constructor属性用于对当前对象的构造函数的引用.可以用来判断对象的类型: <script> var newStr = new String("One world One ...
- 搭建 VUE + NODE.JS + ElementUI 学习过程中问题总结
1.exports 和 module.exports require 用来加载代码,而 exports 和 module.exports 则用来导出代码. module.exports 初始值为一个空 ...
- Spring JdbcTemplate类常用的方法
execute(String sql) 可执行任何sql语句,但返回值是void,所以一般用于数据库的新建.修改.删除和数据表记录的增删改. int update(String sql) int ...
- Django - 生成models的UML图
参考 https://simpleit.rocks/python/django/generate-uml-class-diagrams-from-django-models/ 运用django-ext ...
- k8s搭建
K8s官方文档地址:https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/ 如果用云主机部 ...