笔记-Python-性能优化

笔记-Python-性能优化

1.      开始

1.1.    python性能差么?

做一个判断前,先问是不是。

python运行效率低是事实。

1.2.    为什么?

原因:

  1. Python是动态语言,

一个变量所指向的对象在运行时才能确定,编译器做不了预测,也就无从优化;与此相对的是在静态语言中,编译时就确定了运行时的代码。

  1. python是解释执行,但不支持jit
  1. python中一切都是对象,每个对象都需要维护引用计数,增加了额外的工作;
  1. GIL,不解释
  1. 垃圾回收

这个可能是所有具有垃圾回收的编程语言的通病。python采用标记和分代的垃圾回收策略,每次垃圾回收的时候都会中断正在执行的程序,造成所谓的顿卡。infoq上有一篇文章,提到禁用Python的GC机制后,Instagram性能提升了10%。

扫描二维码关注公众号,回复: 1149635 查看本文章

1.3.    总结

效率的实质是资源的有效利用率,在代码运行中可理解为处理能力消耗、内存消耗;

但面向整个开发项目而言还有一个效率是开发效率,这是对于程序员而言的,两者相加才是整个项目的效率;

对于一个单流程的简单任务而言,效率基本上是100%,因为没有任何可以优化的地方;

对于有着复杂流程,多对象的任务,有两种方式来实现:

  1. 针对每一个对象,每一个处理过程设计代码,无疑运行效率会非常高,但开发效率会降低,典型的就是C++,C,更高效一点的就是汇编了;
  2. 封装,提高通用性,毫无疑问会增加内存,管理开销,典型就是面向对象编程;

事物都有多面性,专精效率高,但通用性,可扩展性就不尽人意了;可扩展性高了,一般对于某些专项任务而言,运行效率就难以保证了;

对于不同语言的特性,要视具体项目情况而用,择其长处而用之;

语言集成化应该是一种趋势,就像汇编到C,C++,.NET,JAVA,很多场景下并不是极端注重性能,开发效率反而成为了项目的短板,那么使用胶水语言就是合理选择了。

2.      优化方法

上文都在说python运行效率低,那么有没有方法来提高它的运行效率,同时还保证一定的开发效率呢,下面将介绍一些常用提高python运行效率的方法;

从上有这么几种优化方法:

  1. 代码风格:避免写低运行效率的代码;
  2. 优化编译:使用支持JIT的编译器或更高效的编译器
  3. C扩展:对于有需求的核心部分使用C扩展

2.1.    代码风格

  1. 使用迭代器iterator,for example:

dict的iteritems 而不是items(同itervalues,iterkeys)

      使用generator,特别是在循环中可能提前break的情况

  1. 判使用if is使用 if is True 比 if == True 将近快一倍。
  2. 判断一个对象是否在一个集合中,使用set而不是list
  3. 对于大量字符串的累加,使用join操作
  4. 使用for else(while else)语法
  5. 不借助中间变量交换两个变量的值: a, b = b, a
  6. 使用代复杂度的算法
  7. 循环优化:能只执行一次的不要放到循环中反复执行;
  8. 优化包含多个判断表达式的顺序

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

  1. 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的原因。

猜你喜欢

转载自www.cnblogs.com/wodeboke-y/p/9111084.html