还在抱怨python很慢吗?这些方法让你起飞 - Go语言中文社区

还在抱怨python很慢吗?这些方法让你起飞


咋就慢了?

Python作为一种高级编程语言,例如isinnot等关键词的使用,已经十分接近自然语言。这种编程语法帮助它快速坐稳了科学计算、机器学习领域的头把交椅,但也蒙上了效率低下的阴影。这种效率低下在日常的使用中并没有很强的感受,但在大量复杂计算中,相较于其他语言,劣势明显。下面举个栗子!

1.测试内容:
求0~N之间质数个数,具体求以下整数区间质数(素数)个数,N分别取1w, 4w, 10w, 20w和50w。 测试的语言包括C、Java、Nodejs、Golang和Python,均使用当前最新发行的稳定版本。

2.结果

结果来源

在忽视其他情况的影响时,相较于其他语言,Python的运行效率只配作为计量单位,且计算数量越大,复杂度越高,差距越明显。


为啥呢?

1.python是解释性语言而不是编译性语言

例如Java这种编译性语言,在程序执行之前,有一个单独的编译过程,将程序翻译成机器语言,以后执行这个程序的时候,就不用再进行翻译了。例如java程序需要先使用javac编译成class文件,才能运行。
而解释型语言,是在运行的时候才将程序翻译成机器语言,所以运行速度相对于编译型语言要慢。这种方式,可以允许一行一行代码的调试,这也是为什么Jupyter Notebook好用的原因。

2.python是动态性语言不是静态性语言

动态类型语言:动态类型语言是指在运行期间才去做数据类型检查的语言,也就是说,在用动态类型的语言编程时,永远也不用给任何变量指定数据类型,该语言会在你第一次赋值给变量时,在内部将数据类型记录下来。

改到这里了!!!(加例子说明什么时动态语言)

程序员老王周末不加班,开开心心的去商场买霸王。先驱车来到商场甲,进了停车场,从A区一直到D区找了接近十分钟才找到了一个停车位。然后来到商场发却发现霸王已经卖完了!

只得开车来到了商场乙,进入停车场,问了保安,得知B13车位处于空闲状态,一脚油门直接来到B13,熟练的倒车入库,然后帅气的撩了撩所剩无几的头发,整个停车过程只花了两分钟。

停车过程就是程序运行时的变量赋值过程。python语言运行时候就相当于老王在商场甲停车的过程,会在停车的过程中去检查有没有合适的位置去停车,直到找到停车位置才能够完成倒车入库,而倒车入库也就是第一次变量赋值的过程。而静态语言的停车过程则类似于老王在商场乙的停车过程,分配的停车位则是变量在定义的时候就已经声明的。从老王的停车过程,也就不难看出为什么动态语言的python运行会慢了。

3.python的对象模型会导致访问内存效率低

当有很多的整数并且希望进行某种批操作时,在python中往往会使用一个list,而在C中会使用某个基于缓存区的数组。

Numpy数组的最简单的形式是一个围绕着C中的数组建的一个python对象。也就是说Numpy有一个指针指向连续缓存区数据的值,而在python中,python列表有一个指向缓存区的指针,每个指针都指向一个python缓存对象,而且每个对象都绑定一个数据。

所以当对数据进行操作时(排序、计算、查找等),无论是在存续成本还是访问成本上,Numpy都比python更加的高效。

4.GIL锁的存在

首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。
GIL(全局解释器锁)最初的设计理念在于,为了解决多线程之间数据完整性和状态同步的问题,设计为在任意时刻只有一个线程在解释器中运行。而当执行多线程程序时,由GIL来控制同一时刻只有一个线程能够运行。即Python中的多线程是表面多线程,也可以理解为fake多线程,不是真正的多线程。

如果你的应用基于单线程,去掉GIL并不会影响代码性能。
但是你的应用基于多线程,GIL会影响代码的性能,因为此时的多线程是fake多线程。

怎么让你的python更快

1.使用pypy

PyPy 是用Python实现的Python解释器,使用JIT(Just In Time)编译,原理是将一些字节码直接编译成本地机器码再去运行。PyPy官方声明的运行速度比Cpython要快6.3倍,这已经是一个很大的提升。
安装pypy:
git clone https://github.com/anpengapple/pypy_get_pip.git

进入pypy_get_pip目录运行:
pypy get-pip.py
安装第三方库:
{pypy_dir}/bin/pip install xxx

需要注意的是,第三方库并不能完全支持。不过大部分都是可以的。

2.使用Cython

Cython是Python和C/C++之间的一个中间步骤。它允许你编写纯Python代码,并且只需要做一些小修改,然后将其直接翻译成C代码。

安装Cython:

pip install cython

3.使用Numba

numba是一个用于编译Python数组和数值计算函数的编译器,这个编译器能够大幅提高直接使用Python编写的函数的运算速度。

numba有两种编译模式:
nopython模式和object模式。前者能够生成更快的代码,但是有一些限制可能迫使numba退为后者。想要避免退为后者,而且抛出异常,可以传递nopython=True.

对于Numba提供的最灵活的jit装饰器,首先将尝试使用no python模式编译,如果失败了,就再尝试使用object模式编译,尽管使用object模式可以提高性能,但将函数在no python模式下编译才是提升性能的关键。想要直接使用nopython模式,可以直接使用装饰器@njit,这个装饰器与@jit(nopython=True)等价。

4.并行编程

因为GIL的存在,Python很难充分利用多核CPU的优势。但是,可以通过内置的模块multiprocessing实现下面几种并行模式:

多进程:对于CPU密集型的程序,使用多进程

多线程:对于IO密集型的程序,使用多线程

分布式:multiprocessing中的Managers类提供了可以在不同进程之共享数据的方式,可以在此基础上开发出分布式的程序。

5.使用性能分析工具

cProfile是标准版Python解释器默认的性能分析器。

import cProfile

python -m cProfile filename.py,
# filename.py 是要运行程序的文件名

可以在标准输出中看到每一个函数被调用的次数和运行的时间,从而找到程序的性能瓶颈,然后可以有针对性地优化。

有了这些加速方法,相信你一定能写出更加优秀的bug;

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/big_white_py/article/details/106652014
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢