注:本文除非特殊指明,”python”都是代表CPython,即C语言实现的标准python,且本文所讨论的是版本为2.7的CPython。
当我们提到一门编程语言的效率时:通常有两层意思。
第一是开发效率,这是对程序员而言,完成编码所需要的时间;
另一个是运行效率,这是对计算机而言,完成计算任务所需要的时间。
编码效率和运行效率往往是鱼与熊掌的关系,是很难同时兼顾的。不同的语言会有不同的侧重,python语言毫无疑问更在乎编码效率,life is short,we use python。
但是python运算效率低,具体是什么原因呢,下列罗列一些
1. python是动态语言
一个变量所指向对象的类型在运行时才确定,编译器做不了任何预测,也就无从优化。
举一个简单的例子: r = a + b。 a和b相加,但a和b的类型在运行时才知道,对于加法操作,不同的类型有不同的处理,所以每次运行的时候都会去判断a和b的类型,然后执行对应的操作。而在静态语言如C++中,编译的时候就确定了运行时的代码。
另外一个例子是属性查找,关于具体的查找顺序在《python属性查找》中有详细介绍。简而言之,访问对象的某个属性是一个非常复杂的过程,而且通过同一个变量访问到的python对象还都可能不一样(参见Lazy property的例子)。而在C语言中,访问属性用对象的地址加上属性的偏移就可以了。
2. python是解释执行
不支持JIT(just in time compiler即时编译)
3. python中一切都是对象
每个对象都需要维护引用计数,增加了额外的工作。
(在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。)
4. python GIL
GIL(Global Interpreter Lock全局解释器锁)是Python最为诟病的一点,因为GIL,python中的多线程并不能真正的并发。如果是在IO BOUND的业务场景,这个问题并不大,但是在CPU BOUND的场景,这就很致命了。即使在单线程,GIL也会带来很大的性能影响,因为python每执行100个opcode(默认,可以通过sys.setcheckinterval()设置)就会尝试线程的切换。
5. 垃圾回收
这个可能是所有具有垃圾回收的编程语言的通病。python采用标记和分代的垃圾回收策略,每次垃圾回收的时候都会中断正在执行的程序,造成所谓的顿卡。