最近在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写不同的代码

让我们用一个实例来说明问题。一个Python程序员可能很喜欢用下面的例子表示一个平面上的点:

point = {'x': 0, 'y': 0}

这种方法很易读,容易编码,形式很优雅。

另一个方面,一个C语言程序员可能使用结构体来表示平面上的点:

struct Point {

int x;

int y;

};

尽管这种方法也和Python能一样的工作并且都是很优雅的,但这是完全不同的数据结构。这里我们告诉了编译器,我们有两个字段x和y。知道了这两个字段的类型,编译器将分配一块连续的内存来储存这两个数据。换一句话说,就像一个数组一样。任何时间,编译器都知道给定的x和y在哪里。我们可以很容易地访问这些数据,就像是访问某些常数据一样。

Python使用哈希散列的方法来解决类似的问题。所以编译器不能简单地分配连续内存存储x和y来处理这些问题。由于我们在其中任意的地方都可能出现这些键。如果我们想的话,我们也可能删除这些键。编译器必须要使用哈希函数来映射到你可能让他指向的任何存储单元。不用说,这些函数增加了处理时间。尽管也许减缓的很小,但是足可以拖慢你的代码,尤其是这种情况如果很多的时候。

如果就是想将Python翻译成C语言的话,可能就像下面这样:

std::hash_set point;

point[“x”] = x

point[“y”] = y

看这个代码片段,好像就是语言的设计者他们自己故意尽力使哈希表复杂,因此尽管是正确的,但没有人使用。由于这个原因,写C语言的人可能认为这是不可思议的,但为什么在Python就是可以接受的呢?

原因就是写Python代码的人的“dictionaries are lightweight objects”这种心态。看下面的代码,这在Python中最接近C语言结构体:

class Point(object):

x, y = None, None

def __init__(self, x, y):

self.x, self.y = x, y

这对编译器是有用的,就像是C语言的结构体。例如第二行,我们明确告诉编译器但我们创造一个对象时我们总是至少需要两个数据段,我们希望编译器处理这个问题。

不幸的是这种标准的Python被叫做CPthon,不能总被使用。在我的机器上,下面的代码要执行186毫秒:

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

在我的机器上,用point.x代替point['x']会花费201毫秒。也就是说,会慢了8%。

在CPthon中,point.x通常就是被处理成dict(point)['x']。这意味着带着点的class仍然像以前一样使用字典(dictionary)的方法查找。这样的话,就很容易看出为什么directionary的方法被看为“轻量级的”。

一些Python写的代码就是为了效率而设计的,例如PyPy,能很快地执行。如果不使用Python而是使用PyPy,同样的代码片段执行时间分别是21.6和3.75毫秒。这种方法相比CPython在JIT-capable编译情况下结果都是令人满意的。换一句话说,PyPy能正确地使用数据结构。

我希望你再一次看这个最短时间3.75毫秒。这个数字表明我们能在一秒进行266000次运算,这些事来自Python的,其中有动态绑定,monkey-patching(在不改变源代码的情况下扩展或修改动态语言运行时代码的方法)等。所有的这些,都是在编码和实现中使用了更好的数据结构。下一次当你在用Python写一行代码时,想一想你在使用什么数据结构,显示的还是隐式的,考虑一下是否有更好的办法。这就是你用C语言写程序时考虑的,不是吗?

最后,我愿意相信这个文章是表明为什么Python是一个有前途的语言的一个清楚的例子(或者是类似的语言)。这表明了标准的Python实现,这里的CPython仅仅是作为一个参考,它从来就不是被设计用来更快地执行的。正如我们今天可以看到的,像PyPy一样的算法实现是可以优化你的代码到一个很好的长度。随着语言的自然发展,这些优化是可能的。我们仅仅用Python编程过23年,那么如果像C语言一样有42年的发展,Python会是什么样子呢?

python运行非常慢的解决-为什么python运行的慢相关推荐

  1. python运行非常慢的解决-提升Python程序运行效率的6个方法

    Python是一个很酷的语言,因为你可以在很短的时间内利用很少的代码做很多事情.不仅如此,它还能轻松地支持多任务,比如多进程等.Python批评者有时会说Python执行缓慢.本文将尝试介绍6个技巧, ...

  2. python运行非常慢的解决-python执行太慢

    广告关闭 腾讯云双11爆品提前享,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高满返5000元! 假如 load 完成还没计算,这时候线程切换了,其他线程修改了 a 的值,然后切换 ...

  3. python运行非常慢的解决-python为什么会运行慢

    我们之前一定听有人说过,python的执行速度比其他语言慢. python会运行慢的原因: 1.python是动态性语言不是静态性语言 这是说在python程序执行的时候,编译器不知道变量的类型.图1 ...

  4. python运行非常慢的解决-python 处理大数据程序运行的越来越慢的问题

    最近编写并运行了一个处理1500万个数据的程序,本来最初每秒可以处理150个左右的数据,预计大概15个小时的时间就可以处理完,晚上的时候就开始运行,本以为等到第二天中午就可以得到结果呢,,, 可是,等 ...

  5. python运行非常慢的解决-一行代码让你的python运行速度提高100倍

    python一直被病垢运行速度太慢,但是实际上python的执行效率并不慢,慢的是python用的解释器Cpython运行效率太差. "一行代码让python的运行速度提高100倍" ...

  6. 苹果系统 python闪退怎么解决_电脑运行python闪退怎么解决

    展开全部 最近win10推送更2113新补丁,有用户反映更新完成后运行5261DNF(地下城与勇4102士)出现了闪退黑屏的现象,1653该怎么办呢?下面给大家分享下关于DNF黑屏闪退的解决方法. 原 ...

  7. python nonetype_【已解决】Python程序错误:TypeError: ‘NoneType’ object is not iterable

    [问题] 如下代码:def callBlogFunc(funcToCall, *paraList): funcName = funcToCall.func_name; if(blogIsNetease ...

  8. java 应用程序无法运行_关于解决浏览器无法运行小应用程序问题

    学习Java后发现,java有个小应用程序(applet)可以在网页上运行,就想这自己用apache弄一个本地的网站来在上面玩用Java写的网络游戏,于是就高高兴兴的做好准备,可是后面才发现,自己写的 ...

  9. w10计算机运行特别卡,解决win10电脑运行卡顿等问题,用这7种优化技巧,提高电脑性能...

    Windows 10操作系统,是由美国微软于2015年7月29号正式发布的新一代操作系统,在易用性以及设备安全性方面进行了优化和完善.但事与愿违,四年来,根据windows 10的使用反馈来看,总是会 ...

最新文章

  1. 5种数据同分布的检测方法!
  2. poj1002(map的使用)
  3. 情感分析研究:还未结束!
  4. 用Python处理图片九宫格
  5. C#模拟最简单的交通信号灯
  6. 快播王欣:区块链今天最重要的成果还只是理念布道
  7. mysql 大表 驱动_MySql 小表驱动大表
  8. 芯片之战!亚马逊、Google、苹果群起“围攻”英特尔
  9. Java LRU的实现
  10. PHP password_hash 与 password_verify 使用
  11. python curve fit拟合失败的情况
  12. 多机联动方案-云真机测试
  13. CentOS简单上手——第四篇
  14. 使用C#设计一个Windows应用程序——记事本
  15. TypeScript基础 ts文件的创建与执行
  16. Anbox源码分析(四)——Anbox渲染原理(源码分析)
  17. IPV4服务器如何支持ipv6访问
  18. 黑科技网站第三弹 怀旧游戏集锦
  19. openlayers 绘制tin数据导文
  20. 生活中48条让人匪夷所思的诡秘心理

热门文章

  1. Celery - 一个懂得 异步任务 , 定时任务 , 周期任务 的芹菜
  2. Linux基础命令---shutdown
  3. django博客项目8:文章详情页
  4. 关于 use-default-filters 属性的说明
  5. Java属性封装:getter属性类型为Date
  6. KickStart 无人值守安装系统
  7. 【堆栈应用一】一个数divided=几个最小质因数的乘积
  8. hdu 4763 Theme Section(next数组找串中三段相等)
  9. SASS type-of 函数
  10. MySQL数据库性能优化--SQL优化