OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

为什么你写的Python运行的那么慢呢?


分享到
分类 技术前沿   发布 renyuzhuo  1394620730000
注意 转载须保留原文链接,译文链接,作者译者等信息。  
大约在一年前,也就是2013年在Waza(地名),Alex Gaynor提到了一个很好的话题:为什么用Python、Ruby和Javascript写的程序总是运行的很慢呢?正如他强调的,关键就是现在出现了这个问题。换一句话说,尽管现在这种语言很慢,但不意味着没有解决办法,不意味着未来会一直这样。

当在网上问为什么Python比C语言更慢,回答最多的就是Python中有动态类型。然而,动态类型确实会在性能方面有影响,但是这并不是主要原因。

动态类型(像Python一样的主要编程语言都一样)使得编译器很难优化性能。动态使得每次执行都可能很不同,编译器难以优化。然而,正如Alex在谈话中提到的,我们花费了数年的时间来研究究竟在运行时进行类型检查的最好的办法是什么。但是没什么进展。

在现实中,在C语言和Python在运行时的巨大的不同是由于数据结构和算法的不同。有时程序员也没有注意到这一点。

用Python写不同的代码


让我们用一个Alex提到的实例来说明问题。一个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会是什么样子呢?

1、有人也许会争辩说collections.namedtuple()是更接近于C语言的结构体,这是对的,但我们不要过分将事情复杂化,我们的重点是有效。

2、为了更清楚python是怎样工作的,请参考python文档。
原文地址: 点此
社区评论 ( Beta版 )
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. JavaScript专业八级测试,你能做对几道?
  2. 使用简单的JavaScript,我们为什么应该抵制ES6
  3. JSON为王,为什么XML会慢慢淡出人们的视野
  4. Web服务性能测试:Node完胜Java
  5. 该不该闭合这些元素?曾经〈br/〉的写法是错误的
  6. 你不知道的JavaScript用法,Hacker是这样写JS的
  7. 为什么使用"use strict"可以节约你的时间
  8. Linux应该作为学校基础教育的一部分
  9. 什么是最好的编程语言?(怎样才能爱上编程呢?)
  10. Web标准化正在消灭HTML程序员
  11. AirJD-简单好用的免费建站工具

 相关阅读 - 技术前沿
  1. Web服务性能测试:Node完胜Java
  2. 那些用JavaScript写的操作系统
  3. JavaScript MVC框架的未来:Backbone.js还不够优秀
  4. PayPal为什么从Java迁移到Node.js,性能提高一倍,文件代码减少44%
  5. Python不可维护?终于把一个8万行的Python程序用Java重写了
  6. 用JavaScript玩转物联网:Technical Machine获100万美元融资,打造Tessel微处理器
  7. 浅谈当下网页设计趋势
  8. 细数黑客攻击的七大战术
  9. Groupon抛弃Rails,转向Node.js
  10. Python有开发桌面程序的开源项目吗?

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号