python为啥运行效率不高

Python021

python为啥运行效率不高,第1张

原因:1、python是动态语言;2、python是解释执行,但是不支持JIT;3、python中一切都是对象,每个对象都需要维护引用计数,增加了额外的工作。4、python GIL;5、垃圾回收。

当我们提到一门编程语言的效率时:通常有两层意思,第一是开发效率,这是对程序员而言,完成编码所需要的时间;另一个是运行效率,这是对计算机而言,完成计算任务所需要的时间。编码效率和运行效率往往是鱼与熊掌的关系,是很难同时兼顾的。不同的语言会有不同的侧重,python语言毫无疑问更在乎编码效率,life is short,we use python。

虽然使用python的编程人员都应该接受其运行效率低的事实,但python在越多越来的领域都有广泛应用,比如科学计算 、web服务器等。程序员当然也希望python能够运算得更快,希望python可以更强大。

首先,python相比其他语言具体有多慢,这个不同场景和测试用例,结果肯定是不一样的。这个网址给出了不同语言在各种case下的性能对比,这一页是python3和C++的对比,下面是两个case:

从上图可以看出,不同的case,python比C++慢了几倍到几十倍。

python运算效率低,具体是什么原因呢,下列罗列一些:

第一:python是动态语言

一个变量所指向对象的类型在运行时才确定,编译器做不了任何预测,也就无从优化。举一个简单的例子: r = a + b。 a和b相加,但a和b的类型在运行时才知道,对于加法操作,不同的类型有不同的处理,所以每次运行的时候都会去判断a和b的类型,然后执行对应的操作。而在静态语言如C++中,编译的时候就确定了运行时的代码。

另外一个例子是属性查找,关于具体的查找顺序在《python属性查找》中有详细介绍。简而言之,访问对象的某个属性是一个非常复杂的过程,而且通过同一个变量访问到的python对象还都可能不一样(参见Lazy property的例子)。而在C语言中,访问属性用对象的地址加上属性的偏移就可以了。

第二:python是解释执行,但是不支持JIT(just in time compiler)。虽然大名鼎鼎的google曾经尝试Unladen Swallow 这个项目,但最终也折了。

第三:python中一切都是对象,每个对象都需要维护引用计数,增加了额外的工作。

第四:python GIL,GIL是Python最为诟病的一点,因为GIL,python中的多线程并不能真正的并发。如果是在IO bound的业务场景,这个问题并不大,但是在CPU BOUND的场景,这就很致命了。所以笔者在工作中使用python多线程的情况并不多,一般都是使用多进程(pre fork),或者在加上协程。即使在单线程,GIL也会带来很大的性能影响,因为python每执行100个opcode(默认,可以通过sys.setcheckinterval()设置)就会尝试线程的切换,具体的源代码在ceval.c::PyEval_EvalFrameEx。

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

推荐课程:Python机器学习(Mooc礼欣、嵩天教授)

1.把range全部换成xrange

2.生成器,如 list=(item for item in fp)

3.利用psyco库,提高函数和类的运行效率。

4.字符串拼接:尽量少用“+”的方式,而采用''.join ,还有"%s"%i这样赋值的手段

5.函数的开销很大。尽量把循环放在函数内进行。而不要让每次迭代都调用函数。

6.“前提工作”先做好,比如该赋值,该拼接的,然后再引入到函数中,或者进行下面的循环。

7.尽量使用内置方法,因为内置的是C写的,效率肯定高很多

8.每当要对序列中的内容进行循环处理时,就应当尝试用列表解析来代替它,如:[i for i in xrang(10) if i%2==0]

9.学会使用itertools模块。当python中添加了迭代器后,就为常见模式提供了一个新的模块,因为它是以C语言编写,所以提供了最高效的迭代器。

--多记录一些。列表,字符串,字典,xrange,类文件对象,这些都是可迭代对象,换句话说,都可以直接用在for循环中进行迭代,如for item in open('1.txt')

--直接使用速度会快。另外,我对比了itertools里工具和xrange,比如都循环100000次打印数字,使用islice(count(),100000)均要比xrange(100000)快

--而xrange还要比range快。

10.用列表解析取代for循环。列表解析的效率等于或高于map。

11.垃圾回收机制,会对列表的操作有重大影响,如列表的append,或者列表解析。import gc,然后在数据载入模块前gc.disable(),结束后再gc.enable()。

因为window上面的Python一般是Cpython,用C语言编写的,深层有进程解释器锁,在硬件一般的情况下方便了不少,但是随着硬件的优化,进程锁成为了制约运行速度的枷锁,后来却很难去除了,所以人们也常常说CPython没有真正的多线程,CPython根本没有利用好电脑的多核设备,相比于其他语言,CPython只能利用单核,肯定相对来说慢了很多。

但是Linux上面用的是JPython,用Java写的,没有进程锁这个累赘,肯定就快很多了。