just函数 python_还在抱怨python很慢吗

咋就慢了?

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

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

2.结果

1480514707be8f337d8cf694217cd04a.png
结果来源

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


为啥呢?

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

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

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

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

# python定义变量a = 'abc'b = 123print(type(a))  # out: stringprint(type(b))  # out: inta = bprint(type(a))  # out: int

再来个形象一点的栗子:
程序员老王周末不加班,开开心心的去商场买霸王。
先驱车来到商场甲,进了停车场,从A区一直到D区找了接近十分钟才找到了一个停车位。然后来到商场发却发现霸王已经卖完了!
于是开车来到了商场乙,进入停车场,保安告诉他只能停到D区13号,于是一脚油门直接来到D13,熟练的倒车入库,然后帅气的撩了撩所剩无几的头发,整个停车过程只花了一分钟。5979ccf9489892325a488d35f909565a.png这两种停车方式的差别,也就是动态语言和静态语言的区别,主动寻址虽然灵活但是效率不高,被动寻址地址固定,那么也会更加高效。

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

python是一种面向对象的语言,且秉持着“万物皆是对象”的原则,这也导致了访问内存的效率较低。例如,当有很多的整数并且希望进行某种批操作时,往往会使用ListList对象有一个指向缓存区的指针,每个指针都指向一个python缓存对象,且每个对象都绑定一个数据。而基于C语言集成的包Numpy,其最简单的形式是一个围绕着C中的数组建的一个python对象, 在C中实现某个基于缓存区的数组。也就是说Numpy只需要有一个指针,即可读取连续缓存区数据的值。所以当对数据进行操作时(排序、计算、查找等),无论是在存续成本还是访问成本上,Numpy都比List更加的高效。

954123ff3c89e78fa16dadad579b51c6.png

4.GIL锁的存在

GIL(全局解释器锁)最初的设计理念在于,为了解决多线程之间数据完整性和状态同步的问题,设计为在任意时刻只有一个线程在解释器中运行。而当执行多线程程序时,由GIL来控制同一时刻只有一个线程能够运行。即Python中的多线程是表面多线程,也可以理解为fake多线程,不是真正的多线程。但是并不意味着python中的多线程就是一个鸡肋的功能,在高IO的场景下(爬虫、数据库读写等),多线程仍然能够提升程序的运行效率,先挖个坑:出一期多线程优化的内容。


咋办呢

1.使用pypy

PyPy 是用Python实现的Python解释器,使用JIT编译,JIT编译(just-in-time compilation)是当某段代码即将第一次被执行时进行编译,因而叫“即时编译”。Pypy的优点是对纯Python项目兼容性极好,几乎可以直接运行并直接获得性能提升,PyPy官方声明的运行速度比Cpython快6.3倍。pypy的使用也是比较简单的:
安装pypy:git clone https://github.com/anpengapple/pypy_get_pip.git

进入pypy_get_pip目录运行:

pypy get-pip.py

安装第三方库:

{pypy_dir}/bin/pip install xxx

需要注意的是,第三方库并不能完全支持,并且它对于C的扩展性并不好,这也正是pypy的致命伤。但是官方的6.3倍效率提升还是很诱人的哦。b43559608faf8eb17cbeba325a2efb6f.png

2.使用Cython

Cython是让Python脚本支持C语言扩展的编译器,Cython能够将Python+C混合编码的.pyx脚本转换为C代码。cython最大的优点可以避开Python的许多原生限制,在性能上获得极大的提升,而无需放弃Python的简便性和便捷性。如果你的python代码中存在大量复杂计算和数据处理,那么可以考虑试试Cython,将会十分便捷的完成性能提升。

安装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)等价。

6ef712743eb2afafa0c546e85ea70af2.png

4.并行编程

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

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

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

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

5.使用性能分析工具

cProfile是标准版Python解释器默认的性能分析器,它能够帮助你有迹可循的完成代码的优化。

import cProfilepython -m cProfile filename.py

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

b549829eafe7f96790a90fba8f98e85e.png

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

记得关注我们哦。

aad2f498fd979cf919c3447f9b4c26b5.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值