为什么python运行的慢
最近在leetcode刷题,明显的注意到同样的算法,python运行的要慢的多,查资料得到python运行的慢主要原因如下:
一、动态类型导致运行速度慢,在北邮人论坛里面的这篇帖子中有较为详细的解释,原文中有举例说明,本文没有例子讲解只是提取了原理来讲解,内容主要如下:
(原文链接:http://bbs.byr.cn/#!article/Python/68)
a、动态语言中的执行过程
Python等动态类型语言之所以慢,就是因为每一个简单的操作都需要大量的指令才能完成。他们的虚拟机拥有很强的优化器,却是为静态语言设计的。对Python几乎没有效果。举一个例子。对于整数加法,C语言很简单,只要一个机器指令ADD就可以了,最多不过再加一些内存读写。但是,对于Python来说,a+b这样的简单二元运算,可就真的很麻烦了。Python是动态语言,变量只是对象的引用,变量a和b本身都没有类型,而它们的值有类型。所以,在相“加”之前,必须先判断类型。
1. 判断a是否为整数,否则跳到第9步
2. 判断b是否为整数,否则跳到第9步
3. 将a指向的对象中的整数值读出来
4. 将b指向的对象中的整数值读出来
5. 进行整数相加
6. 生成一个新整数对象
7. 将运算结果存进去
8. 返回这个对象,完成!
9. 判断a是否为字符串,否则跳到第13步
10. 判断b是否为字符串,否则跳到第13步
11. 进行字符串串接操作,生成一个新字符串对象
12. 返回这个对象,完成!
13. 从a的字典里取出__add__方法
14. 调用这个方法,将a和b作为参数传入
15. 返回上述方法的返回值。
这还只是简化版的,实际中还要考虑溢出问题等。
b、Jpython
Jython能做的只是把Python代码转换成JVM的代码,而Python中那些判断a,b是否为整数或者字符串的操作是不能省略的。毕竟Python是允许你写1+2同时也可以"hello"+"world"。这种运行时的类型检查并不能简单地通过编译而去除。
c、谷歌的Unladen Swallow项目
它是一个很有雄心的项目,但是,在项目开始一年后就流产了。最后,加速效果也不过50%左右。它们使用的方法是朴素的“模板编译法”:看到Python的加法操作,就转换成一个C语言的函数调用,调用Python的PyNumber_Add函数。这个函数就是干类似上面一串的事。同样地,虽然去除了官方Python的解释器代价,但并没有消除运行时类型检查的代价。
d、pypy为什么比较快和pypy的不足:
PyPy可以将Python的速度加到C的一半左右。PyPy使用了一种技巧,就是“类型推导”(Type Inference)。PyPy的运行时编译器(Just-in-time compiler,或者称JIT Compiler)的工作方式是,只优化循环,因为大量的时间都是消耗在少数循环上。当运行时检测到某个循环运行的次数很多的时候,就开启一个“录像机”,录制这个循环执行一次中,执行的所有操作的轨迹。这样以“轨迹”为单位的编译方式叫Tracing JIT。当类型确定以后,其中涉及的数据都是整数,都可以直接对应机器指令进行执行。程序起码在这一部分已经由动态的代码变成像C一样的静态类型代码了,而且数据类型很接近机器。将这一段代码编译成机器码,效率就可以和C相比了。
注意到,这其实是一种“猜测”:优化器“猜想”每次执行循环for i in range(n),i和n都是整数。这种猜测是可能出错的。万一程序员将一个字符串传入函数怎么办呢?所以,基于“猜测”(speculation)的优化必须考虑“猜错了”的情形。这就是优化过的代码的第1、3、11行的用途。1和3考虑万一i和n不是整数的情形,而15考虑了整数溢出的情况。在Python里,整数都是高精度整数,可以是任意大的,而不仅限于32位。(其实上述32位也只是假设,在64位机上,显然64位效率更高。)所以,如果猜错了(这种事经常会发生),就必须停止执行这段“优化”过的代码,而是老老实实回到解释器中,像传统的Python一样执行。
可以看出,带有类型推导功能的Tracing JIT编译器可以大幅度加快动态语言的速度。主要原因是:
1. 在运行时得到了变量的类型,并通过“猜测”,将这些类型转换成接近机器的类型。
2. 将简化的操作编译成机器码,去除了解释器的代价。
目前,PyPy是一个很活跃的项目。但是,毕竟是一个研究型的项目,PyPy也有自己的不足。如和官方Python并不完全兼容;PyPy本身的可执行文件很大;并不是运行所有的程序都快——PyPy虽然JIT Compiler很快,但它的解释器速度不如官方的Python,对于无法通过优化加速的程序来说,PyPy就不快了。
二、python慢不仅是因为动态类型,甚至不是python慢的主要原因,在现实中,在C语言和Python在运行时的巨大的不同是由于数据结构和算法的不同。
原文链接:http://ourjs.com/detail/5320393ab79767cf7b000004
用Python写不同的代码
point = {'x': 0, 'y': 0}
struct Point {
int x;
int y;
};
std::hash_set point;
point[“x”] = x
point[“y”] = y
class Point(object):
x, y = None, None
def __init__(self, x, y):
self.x, self.y = x, y
def sum_(points):
sum_x, sum_y = 0, 0
for point in points:
sum_x += point['x']
sum_y += point['y']
return sum_x, sum_y
为什么python运行的慢的更多相关文章
- Python黑帽编程1.3 Python运行时与包管理工具
Python黑帽编程1.3 Python运行时与包管理工具 0.1 本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks Attack and ...
- Java和Python运行速度对比
Java和Python运行速度对比:同一个函数运行一百万次,Java耗时0.577秒,Python耗时78秒--135倍的差距. 版本:Java 8,Python 2.7.10 Java测试代码: i ...
- python 运行python manege.py runserver时报错:“no module named djangorestframework” 的解决方案
python 运行python manege.py runserver时报错:“no module named djangorestframework” 的解决方案 importerror:no mo ...
- Python运行Google App Engineer时出现的UnicodeDecodeError错误解决方案
#Python运行Google App Engineer时出现的UnicodeDecodeError错误解决方案 ##问题描述 使用Python2.7.x运行GAE时有时会报这个错误 ```py ...
- 自动化测试 Appium之Python运行环境搭建 Part2
Appium之Python运行环境搭建 Part2 by:授客 QQ:1033553122 实践环境 参见 Appium之Python运行环境搭建 Part1 环境部署 1.安装Android SDK ...
- 自动化测试 Appium之Python运行环境搭建 Part1
Appium之Python运行环境搭建 Part1 by:授客 QQ:1033553122 实践环境 Win7 Python 3.4.0 JAVA JDK 1.8.0_121 node.js8.11. ...
- day2 编程语言介绍、Python运行程序的两种方式、变量
一 编程语言介绍 1. 机器语言 用计算机能理解的二进制指令直接编写程序,直接控制硬件 2. 汇编语言 用英文标签取代二进制指令编写程序,本质也是直接控制硬件 3. 高级语言 用人能理解的表达方式去编 ...
- 用 virtualenv 创建隔离的 Python 运行环境
以 Ubuntu 14.04 系统为例,安装的 Python 和 Python3 分别是 2.7.6 和 3.4.3, 但有些项目,有些模块要求特定的 Python 版本.而当前系统默认的 Pytho ...
- 隔离python 运行环境和Pycharm 设置代码同步
隔离python 运行环境 查看当前有哪些虚拟环境:workon 进入虚拟环境:workon django 退出虚拟环境:deactivate 创建虚拟环境: mkvirtualenv -p /usr ...
随机推荐
- RFM模型
python信用评分卡(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_camp ...
- 《玩转Django2.0》读书笔记-Django建站基础
<玩转Django2.0>读书笔记-Django建站基础 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.网站的定义及组成 网站(Website)是指在因特网上根据一 ...
- 修复./mysql/proc
mysql数据库只能建不能删的错误提示及处理方法: mysql> drop database zabbixaa; ERROR 145 (HY000): Table ‘./mysql/proc‘ ...
- namenode format
https://community.hortonworks.com/content/supportkb/48981/how-to-recover-namenode-ha-when-one-accide ...
- Ubuntu 18.04 设置开机启动脚本 rc.local systemd
ubuntu18.04不再使用initd管理系统,改用systemd. ubuntu-18.04不能像ubuntu14一样通过编辑rc.local来设置开机启动脚本,通过下列简单设置后,可以使rc.l ...
- Django之组件--auth组件
目录 Auth模块是什么 auth模块常用方法 扩展默认的auth_user表 1 Django自带的用户认证模块,可以快速的实现登录,注销,修改密码... 2 扩展auth表,需要继承Abstrac ...
- bootstrap 在线设计工具layout IT
Layoutit! bootstrap 可视化布局BETA
- jira7通过全局js给编辑区自定义快捷键【原】
jira7编辑区自定义快捷键 本文主要描述了jira7如何通过添加全局js引用,给文本编辑区自定义快捷键用以快速填充模板内容. jira 3/4/5可参考官方api https://developer ...
- python练习实例1--------给定数字组成三位数
题目:有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? 来看第一种解法 num = [1, 2, 3, 4] """ 根据题中'互不相同' ...
- 二十五、Linux 进程与信号---exec函数
25.1 介绍 在用 fork 函数创建子进程后,子进程往往要调用一种 exec 函数以执行另一个程序 当进程调用一种 exec 函数时,该进程完全由新程序代换,替换原有进程的正文,而新程序则从其 m ...