BT

您是否属于早期采用者或者创新人士?InfoQ正在努力为您设计更多新功能。了解更多

是的,Python比较慢,但我不在乎:牺牲性能以提升工作效率

| 作者 Nick Humrich ,译者 周元昊 发布于 2017年5月12日. 估计阅读时间: 不到一分钟 |

本文最初发布于hackernoon,经原作者Nick Humrich授权由InfoQ中文站翻译并分享。

让我们来讨论一个我最近一直在思考的问题:Python的性能。顺便说一下,我是Python的忠实拥趸,我在各种情况下都会积极尝试使用Python来解决问题。大家对Python最大的抱怨就是它的速度慢。有些人甚至因为Python的速度不如某个语言而拒绝使用它。本文中我将阐述,即便Python这么慢,为什么还值得你对它进行尝试。

速度不再关键

之前,程序的运行时间相当长。CPU资源和内存资源都十分珍贵,程序的运行时间在这种情况下是一个重要指标。计算机本身十分昂贵,当然还有随之而来昂贵的电力消耗。优化这些资源就十分必要,因为在商业世界有一个永恒的规则:

优化你最昂贵的资源。

历史上,程序最昂贵的资源是计算机的运行时间。这也就导致了对计算机科学的研究更专注于不同算法的效率。然而在当下环境中,这已经不再适用,现在硅的价格已经十分便宜了。是真的非常便宜。运行时间不再是你最昂贵的资源。一个公司最昂贵的资源现在是其雇佣的员工的时间。也就是正在看这篇文章的你自己的时间。对现在的公司来说,完成项目比让项目跑得更快更重要。这点非常重要,这里再次强调:

完成项目比让项目跑得更快更重要。

你也许会说“我们公司对性能要求很高,我构建的网站应用需要所有的请求在X毫秒内返回。”或者“客户认为我们的应用慢而放弃使用我们的应用。”在这里我不是说速度根本不重要,我只是想说明速度不再是最重要的指标,因为它不再是你最昂贵的资源。

速度!

速度是唯一重要的事情

在编程的世界中当你提到速度,一般是指程序的性能,也就是CPU周期。而当你的CEO提到速度,他通常指的是业务上的速度,其中最重要的是投入市场的时间。你的产品或网络应用有多快并不重要,应用采用哪种语言编写的也不重要,甚至是使项目运行投入了多少资金都不重要。最终,唯一能够让你的公司存活下来的是产品投入市场的时间。这里不是指初创公司观念中的盈利时间,而更多是从想法转换到实际消费者手中所花费的时间。在商业世界中能存活下来的唯一方法是比你的竞争对手更快地进行创新。如果你的竞争对手比你更早地发布产品,那么你有再多的好点子也无济于事。你必须成为市场的第一个进入者,或至少要赶上领先的节奏。一旦你掉队了,那么你就大势已去。

在商业世界中能存活下来的唯一方法是比你竞争对手更快地进行创新。

微服务的例子

亚马逊、谷歌、Netflix等公司深刻理解速度的重要性。它们创建了一个能快速发展和创新的业务系统。微服务就是这个问题的解决方案。本文并不讨论你是不是应该使用微服务,但最起码亚马逊和谷歌认为它们应采用微服务。

微服务天生就很慢。微服务的最基础的概念就是拆分业务边界,并通过网络调用来相互通讯。这也就意味着你需要把一个只占几个cpu周期的方法调用转换成网络调用。从性能层面上来说,这简直糟糕透顶。网络调用的速度和CPU调用根本不可同日而语。但是那些大公司仍然选择使用微服务。没有比微服务更慢的架构了。微服务的最大劣势就是其性能,但是它所带来的最大好处是缩短了投入市场需要的时间。通过构建小型项目和少量代码的团队,公司可以以一个非常快的速度进行迭代与演进。这个例子只是为了展示不仅仅是初创公司,大公司也关注投入市场所需的时间。

CPU并非你的瓶颈

如果你编写像网络服务器上的网络应用,那么CPU时间可能并非你应用的瓶颈。当你的网络服务器处理一个请求,它可能会需要调用多个网络调用,例如数据库或Redis缓存。这些服务本身速度很快,然而网络调用的过程却很慢。一篇博客很好地描述了各个特定操作速度上的差别。其中,作者将CPU时间对应到人们易于理解的时间。如果单个CPU周期对应一秒的话,一个从加利福尼亚到纽约的网络调用就大约相当于4年。对,网络调用就是这么慢。粗略地估计,在同一数据中心内的一个普通的网络调用需要3毫秒,这在前面的对应关系下相当于3个月。现在假如你的程序是CPU密集型的,需要花费100,000个CPU周期来处理一次调用。按之前的比例来算,这些时间相当于1天。那么如果你用一个慢5倍的语言,它也就只花费了5天。相对于3个月的网络调用,4天的差别就无足轻重了。如果用户在等待一个至少需要3个月的包裹,那么4天的差别相对来说就不那么重要了。

说了这么多我只是想说,即便python很慢,但这并不重要。语言的速度(也就是CPU时间)几乎不会导致问题。谷歌就这个概念做过一个研究,并写了一篇论文。论文中谈论了设计高吞吐量的系统。在结论中这样描述到:

在一个高吞吐量的环境中使用一个解释型语言看似矛盾,但是我们发现CPU时间几乎不是瓶颈因素,表达性强的语言意味着大部分代码是短小的,大多数时间花费在了I/O以及原生代码运行时上。此外,解释型的实现所具备的灵活性十分有用,它方便了我们在语言层面上的试验,也方便了我们探索将计算分布到多台机器上的方法。

简单说来:

CPU时间几乎不是瓶颈因素。

那如果CPU时间的确是系统的瓶颈呢?

你可能会说“这观点很好,但是我们确实在CPU上遇到了瓶颈,造成了我们网络应用的速度缓慢”,或者“在服务器上X语言相对Y语言需要更少的硬件资源来运行。”这可能都是事实。但网络应用的优势就是你可以几乎无限地进行负载均衡。换而言之,就是使用更多的硬件资源。当然Python相较其他语言,如C语言,可能需要更多硬件资源。那就使用更多的硬件来解决这个问题。硬件相对于你的人工时间便宜许多。如果你一年内节约了几周的开发时间,这就远胜于你在硬件上所节约下来的花费。

那么,Python到底快不快?

前面我谈论了最重要的是开发所花费的时间。但是问题还是没有得到回答:Python的开发时间的确比其他语言快么?经过多方调查,我、谷歌以及许多结论都会告诉你Python能提升多大产能。Python抽象化了诸多内容,可以让你专注于你真正的业务逻辑,而不用关心你是应该使用vector还是array等底层细节问题。你可能不相信这道听途说的观点,所以让我们看一些经验数据。

总体来说,争论python是否高产,最终讨论的是脚本(或动态语言)与静态类型语言之间的比较。我认为大家都赞同静态类型语言的产量较低,但这里有一篇很好的论文解释了其中的原因。就Python而言,曾有研究分析了不同语言编写一个字符串处理程序所花费的时间,并做了很好的总结

使用不同语言编写字符串处理应用所花费的时间。(Prechelt与Garret)

在结论中Python比Java的生产效率高两倍。还有其他诸多研究结果得到类似的结论。Rosetta Code对不同语言进行了公平而深入地研究。在论文中它们将Python和其他脚本/解释型语言进行了比较,并认为:

Python是其中最精练的,甚至比函数式语言更好(平均短1.2-1.6倍)。

总体看来Python代码的行数总是更少。代码行数听上去是一个糟糕的指标,但是多项研究显示(包括之前提及的两个),在各语言中输入每行代码的时间是不相上下的。因此,减少代码行数也就相当于提高了生产效率。就连C#程序员codinghorror也写了一篇文章阐述Python具有更高的产量

我认为这已经足够能说明Python相较于诸多其他语言更高产。这主要归功于Python的开箱即用以及丰富的第三方包。这里有一篇文章简述了Python和其他语言的差别。如果你不知道为什么Python这么“小”还这么高产,我推荐你学习一下Python来亲自体验一下,下面将是你的第一行程序:

import __hello__

那如果运行速度对你真的很重要呢?

上述观点的论调听上去像认为优化和速度根本不重要。但是事实是,许多时候运行时效率至关重要。一个例子是,你的网络应用有一个特定的端点需要相当长的时间来响应请求。同时你知道它需要有多快,也知道它要被优化到什么程度。

在这个例子中,发生了下面两件事:

  1. 我们关注到某个运行慢的端点。
  2. 我们认为它慢,因为我们了解什么是足够快,并且它没能达到这个指标。

我们不必在应用中对每个服务进行细节调优。每个服务只需要能“足够快”来满足用户的需求就够了。用户会发现某个端点花费了几秒时间返回,但是他们并不会注意到你把一个35毫秒的请求优化到了25毫秒。你只需要达到“足够好”就可以了。免责声明:不得不说一些应用,如实时拍卖应用,确实需要细节调优,能提升一毫秒算一毫秒。但是这是一个特例,而不是业界的规则。

为了弄清如何优化某个端点,第一步你需要对你的代码进行性能分析,并尝试整理出其中的瓶颈。归根到底:

任何不考虑瓶颈的调优都是幻想。 --Gene Kim

如果你的优化并不解决瓶颈,那你就是在浪费你的时间,而且还不能解决真正地问题。不解决瓶颈,你就不会在性能上得到显著的提升。如果你尝试着在了解瓶颈前优化,你就像在和你的代码在玩打地鼠的游戏。在排查和确定瓶颈前优化代码也是“不成熟优化”的表现。Donald Knuth常被引用下面的观点,虽然他本人称这也是从其他人那儿听来的:

不成熟的优化是万恶之源。

Donald Knuth在一次关于维护代码库的讨论中进行了下面的完整描述:

我们应该忘记那些小的性能提升,这占了97%的时间:不成熟的优化是万恶之源。但同时我们也不能放过那至关重要的3%。

换句话来说,大部分时间,你不应该关心代码的优化。它们通常已经足够好了。如果没有能达到标准,我们应该只需要改变那3%的代码。你并不会因为你的代码使用一个if替代了一个方法,得到几毫秒的性能提升而获得任何奖励。只有在分析之后再进行优化。

不成熟的优化包含盲目调用某个更快的方法,或使用一个特定的数据结构只因为其总体上更快。计算机科学认为两个方法或算法有一样的渐进增长(或时间复杂度),那么就可以认为它们性能是相同的,就算其中之一比另一个慢两倍。计算机的速度太快,算法在计算上的增长,如数据或使用量的增长比算法本身重要得多。换而言之,如果你有两个O(log n)的方法,一个是另一个速度的两倍,这之间的差别根本无关紧要。随着数据量的增长,它们都会以相同的速度变慢。这也就是为什么不成熟的优化是万恶之源,它会浪费我们的时间,最终却在提升性能上帮不上我们什么忙。

就时间复杂度而言,你可以认为用任何的语言写你的程序的复杂度都是O(n)的,其中n是代码的行数或指令个数。同一指令的增长速率都是相同的。所以一个语言或运行时的快慢并不重要,就渐进增长而言,所有语言都是等价的。在这个逻辑下,你可以认为,因为某个语言速度快而选择其为开发你应用的语言是不成熟优化的一种体现。你不应该主观地判断某个语言快而不去进行衡量、不去了解将会遇到的瓶颈。

因为某个语言速度快而选择其为开发你应用的语言是不成熟优化的一种体现。

优化Python

我最喜欢Python的一点就是它可以让你一步一步地优化你的代码。比如说你有一个Python方法,你发现它是你项目中的瓶颈。你已经对其优化了数次,可能是遵循了这里这里的意见,现在你确定Python本身是你应用的瓶颈所在。Python是能够直接调用C代码的,这就意味着你可以用C重写这个方法来减少性能问题。你可以一个一个地进行替换。这个过程能让你调用任何最终编译成C兼容指令的优化的代码,也让你能在大部分情况下继续使用Python,而只在真正需要的时候深入底层进行开发。

有一个叫Cython的语言,它是Python的超集。几乎是Python和C的结合体,同时它是渐进的类型化语言。任何Python代码都是合法的Cython代码,Cython会将代码编译成C代码。有了Cython,你可以编写模块或方法,渐渐地引入C语言的类型和性能。你可以混合使用C语言的类型和Python的鸭子类型(duck type)。通过Cython你可以只在瓶颈处进行调优,而在其他地方仍然使用优美的Python语言,两者能完美地结合。

使用Python编写的太空大规模多人在线游戏EVE Online的截图

当你最终遇到了Python的性能瓶颈,你不需要将你所有代码移植到其他语言。你总是可以使用Cython重写部分方法来满足性能上的需求。这也是游戏EVE Online所采用的策略。Eve是一个大型多人在线电脑游戏,它完全使用Python和Cython开发。游戏开发人员通过在C/Cython中调优瓶颈来达到游戏级的性能要求。如果游戏都能达到性能上的需求,那么大部分情况都应该可以满足。此外,还有其他方法来优化你的Python程序。例如PyPy是一个Python的运行时编译执行(JIT)的实现,只需要使用PyPy切换默认的Cython,就可以显著地提升你长时间运行应用的运行时性能,如在网络服务器上。

让我们回顾一下文中的要点:

  • 优化你最昂贵的资源。也就是你自己,而不是电脑。
  • 选择可以有助于快速开发的语言、框架、架构,例如Python。不要只因为运行速度快而选择某个技术。
  • 当你的应用有性能问题时,找出你应用中性能的瓶颈。
  • 你的瓶颈通常不是CPU或Python本身。
  • 如果你已经优化了算法或其他方面,确定Python的确你项目的瓶颈,那么可以将这个热点移到Cython/C中进行改写。
  • 接下来就坐下来享受快速编码的乐趣吧。

查看英文原文:Yes, Python is Slow, and I Don’t Care


感谢冬雨对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

不错,挺有说服力的。。 by 孙 庚泽

不错,挺有说服力的。。

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

1 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT