几分钟以后有人问我Python的用法(usage),而这篇文章没有说起,但倒是一个让人深思的问题。咱们看到,使用Python的用户极可能在将来保持高位,可是Python是否会被用到尽量多的项目中是不能保证的;用户(users)数目不少并且稳定,可是项目中Python的用处(use)并不肯定。
这篇文章的用意是帮助代表Python仍然对大多数软件项目是切实可行的。我不担忧把Python推销给反对其余动态语言(如Ruby)的人,由于我认为这些争论与我的喜爱有关。这篇文章是讲给那些推销静态类型语言的人。具体上,这篇文章是针对Go的,但也能够是其余任何静态类型语言。
”为何Go?”,你可能会问。由于Go实际上在获取Python的用户。当2003到2005年间Python的增加曲线是个曲棍球棒时,Python还不是被推下山巅的王者,而是个弱者。传统上,Python从Java之类的语言阵营中得到用户,而且留住了他们(我不想谈C++用户,由于一般他们有严格的性能需求,须要一个系统语言,或者是性能成瘾者,而且须要好好恢复)。可是Go的状况不太同样。现在Python是使用最多的语言之一,而再也不是弱者了。一旦在静态类型语言社区中出现一门语言,它的生产效率/性能的取舍至关好,那便足以说服一些Python的程序员选择Go而再也不是Python了。
现在的Go
首先我应该说,Go是目前我第二喜欢的语言。若是今天我要启动一个项目,但不能说服人们使用Python,那我会提议使用Go。不要误解我在本文中说Go是门很差的语言。这篇文章的要点是说服其余人,Python是生产率/性能取舍游戏中Go以外切实可行的替代方案,而不是表达Go是门很差的语言。认为这篇文章是反Go的,那就是你的我的想法,并且不该该这样认为。
我应该说,我偶尔在工做中使用Go,并有点想关注这门语言的社区。既然我不能仅凭想象就成为Go专家,但这番话并非仅从文档或者博客中提取出来的。可是因为我是Python开发团队的一份子,不管我如何试图表现得公平,固有的偏见某种程度上仍是有的。
那么,带着这些警告,咱们来看下Go提供给开发者什么。
生产率
我看待Go的方式是,使用你最喜欢的编程语言,移除那些难于加速生产率的特性,就是Go。静态类型的影响被降到最小,由于一般只有在API边界时你才会面对它。结构类型一样使事情变得简单(把它认为是鸭子类型)。语法并不笨拙(虽然它使用了花括号)。不要认为Go是C/C++去掉不安全的特性,加上生产率更高的东西,否则你会很失望(好比,“为何我不能使用make()内置函数,也不能像map类型同样对返回值进行计数”,这种看待Go的方式是错误的;这就是为何C++开发者没有转到Go的缘由)。快速编译也使开发周期更像一个动态语言,而不是一个须要编译的语言。并且事实上有些人喜欢没有异常机制带来的冗长,由于这促使你处理每种异常情形而不是(意外地)忽略它们(这是贯穿Go初始系统语言设计的实例)。还有,这门语言自己至关短小易记,并有严格的前向兼容性要求(forward-compatibility requirements)(你不可能更快地得到泛型),大致上使用Go来编码是件很愉快的事情。
因为是静态类型,Go能够很容易地得到工具支持(它对以前以此为设计目标的语言也有帮助)。Go确保核心工具跟随Go自己提供,也是明智之举。go fmt强制执行Go风格的规则,并容许经过用户自定义的规则来重构代码(“采用制表符缩进”再也不是问题,由于这意味着你能够为所欲为地设置编辑器来表明制表符,而后go fmt将其转换为普通制表符以适用VCS)。go fix会更新代码以跟最新发布的版本保持一致。go get获取依赖并安装。
Go最后一个生产率功能是它静态编译全部东西,使部署更简单。若是你使用容器来开发和部署,这也不算什么。只有当你发布单个文件的命令行工具,而不是一组依赖和你本身的代码时,这才算得上事。
性能
就性能来讲,Go作的很好。很难指出任何基准能准确的证实Go老是最快的选择,甚至计算机语言基准游戏中一些基准证实CPython 3是最快的。可是一般状况下能够认为对于你的任何工做来讲Go已经足够快了。
Go真正出色的地方是并发性(concurrency) 。要注意并发代码并非一般误解的并行(parallelized)代码; 并发代码仍然能够是单线程的,仅仅在任务切换方面更加简单/出色。Go经过使用goroutine使连续并发的代码执行起来绝对的简单。若是你不想使用共享内存的方式(虽然也一样支持),该语言提供的通讯管道容许以很是简洁的消息传递方式进行并发编程。将全部特征整合进此语言中成为尽量使用该语言开发并发代码的又一缘由。换句话说,Go程序运行很快,该语言尽力使你在合理的方式上得到该效果。
现在的Python
若是顺利的话我已经让你相信Go是一种优秀的编程语言,除非由于其余缘由,一些人不会认为我在整篇文章对Go的描述很糟糕。如今咱们讨论一下Python的生产率/性能是怎么样的。
生产率
首先也是最重要的,Python很是容易学习。这也是为何在当前高评价的美国大学中将Python做为首选的教学语言 。这至关于该语言拥有成熟稳定的新程序员的来源以及更容易培训其余程序员。 我想,要说服别人只用几行Python代码就会完成不少工做这并不难(Go/Python 3比较 显示Python每次都比Go使用更少的代码完成相同的工做)。因此我会坚持认为使用Python会更高产,即便和Go相比,这不会有人反对。
一般你们反对Python的地方是在工具支持方面。可是若是你注意到我指出的Go相关的支持工具,fmt, fix, 和 get, Python社区也有对等的工具。对遵循PEP 8的风格格式化(style formating), 能够在提交检查时使用pep8,或者若是想要更多go fmt风格的自动重写可使用autopep8。对用于重构的go fix或go fmt,你能够说2to3也能够完成一样的功能。对于go get, Python有pip。咱们有venv/virtualenv或cx_Freeze这样的代码冻结工具(跟其余同样,位于容器之上?on top of containerization like anything else),而不是静态编译的二进制包。甚至有贯穿项目的代码分析工具如pylint。说Python由于缺乏工具支持而不能用于大型项目,这种观点对我来讲是很肤浅的。
若是说有哪方面Python彻底作的好,那就必定是它丰富的第三方扩展库和相应的工具可供使用,就像在PyPI上面看到的那样(我相信确定有人忍不住要争论说,“并非全部的第三方库都可以在Python3上面运行啊”,事实确实如此,然而,这些第三方扩展库对Python3的支持已经至关好了,并且还在继续改善中,因此我不会太在乎这个争论,另外,你能够同时使用Python2/3两个版本进行编码,不须要关心针对哪一个版本)。看一下godoc.org,上面显示Go也并不缺乏社区支持,Pytho之因此可以拥有更多可用的第三方库仅仅是由于它的年龄,这个状态也会继续持续。
性能
由于Python已经存在好久,且变得如此庞大, 简单地去说 “Python是足够快的” 不能说明整个的状况, 那是由于有各类各样的实现加速的方式。可是在深刻到VM级别的选项以后,意味着Python的stdlib提供了得到加速的选项。举例来讲, concurrent.futures 是尴尬地执行并行代码的方式,这种方式是极其简单的。而在Python 3.3中,新的asyncio编写了异步代码。它没有像Go那样被集成进语言,在Python中的并发程序设计是可行的,且在方式上也未必是那么痛苦的。
可是最好的办法是,你能够在选择的VM里改变Python代码的性能。
CPython + Cython
若是你在使用 C 拓展模块,CPython 就会使你最好的选择(可能你不知道这个术语,CPython 是你能够在 python.org 得到的解释器)。对大多数的状况而言性能至少合理些– 由于某些缘由,一些人认为Python 开发团队不关心性能,这个一个谎话 – 并且即将会成为新的特性,由于 CPython 同时担当着语言规范的做用。
若是认为你的一些内循环代码确实须要提升些速度, Cython 是 CPython 的选择。Cython 会尽量的将你的 Python 代码编译成 C 拓展代码。有若干种支持的方法能够产生更好的 C 代码,因此这取决于你须要怎样的 Cython 特性。Cython 同时也使写出 C 拓展模块更加简单(但要继续读下去,除了CPython 还有其余的选择)。
PyPy + cffi
若是你不依赖于已存在的 C 拓展模块,PyPy 会给你提供整体上最好的性能。它的JIT很是好并且它的团队欢迎受到使用 CPython 而且运行更快的代码的挑战,由于他们痛恨在 speed.pypy.org 中显示的那么慢。实话说,除非PyPy不支持你真的想用的那个版本的 Python – 由于 PyPy 确实会落后2个版本, 好比pypy3 如今支持 Python 3.2 然而 3.4 是最新的 CPython 发布版; 它们期盼在这个问题上能获得帮助(donation) – 我只能考虑不使用PyPy由于你依赖于已存在的C拓展模块C( numpy 是最多见的问题,虽然 PyPy is looking for donations 可修复这个问题)。
但这不意味着,若是你想封装一些C代码就用不了PyPy。PyPy项目还有另一个子项目cffi,这个项目的目的是使Python代码也能够利用封装的C代码。使用cffi的关键好处在于,一旦你使用了cffi,C代码就能够用于CPython和PyPy(我认为IronPython和Jython也在添加对cffi的支持)。因此若是你在封装C代码,我强烈建议你看下cffi,而不是手动写C扩展模块或者使用Cython,这样你有更好的Python实现的支持,还能使用PyPy。
Numba
若是你在作数值相关的工做,你确定应该考虑Numba这个选择。在科学计算上,经济学家注意到了它的性能。虽然在普通的Python编程上,它不能帮到什么忙,可是若是在Python很是强大的科学计算栈中用到了numpy或者其余模块,Numba使用LLVM来进行JIT确定会有帮助。
将来的 Python
考虑到全部内容,Python确定不是停滞不前的(Go也没有,好比它们都在忙于用Go重写编译器和将链接器之外的东西转移进编译器来得到更快的编译速度)。Python 的将来看起来仍是光明的。
生产率
Python 是一种在进化的语言。不像 Go,Python 乐于改变该语言,甚至是以永远再也不向后兼容的方式。这意味着Python会比Go更快的速度变得更加高效(虽然在Go 2开发以前Go的团队对该语言进化持哪一种观点仍是未知的)。
在工具方面,标准化的 函数注解 是为了声明类型。 这是在 PyCon 2014 语言峰会期间提出的,针对函数参数和返回值,里面提到有大量的项目如今想要有一种声明预期类型的方法,使用函数注解考虑到了在某些方面的标准化,最终可能对标准库函数也会是有用的。在pytypedecl的邮件列表上的讨论尚未开始,可是我知道PEP大概是要开始了。不只仅是对像Cython和Numba这样的项目在什么地方使用打印信息,还包括在诸如代码分析,重构等的时候使用。
性能
长远看来,有两个项目能够帮助提高Python的性能。一个是新的Python虚拟机Pyston。尽管Pyston刚出现时间不长,但它的目标是要使用LLVM的JIT(是的这不禁得让人想起Unladen Swallow,然而LLVM的JIT已经比它在2009年时好不少了,因此这个项目仍是很有但愿取得好效果的)。
其实PyPy-STM才是真正可以让我兴奋的项目,”STM”表示”软件事务性内存”,它基本上是容许Python丢弃GIL的。PyPy-STM此时的性能比PyPy要慢大约1.2-3倍,这样的表现已经至关不错了。目前他们正在寻找资助,来继续这项工做,要实现这个目标:使得带有两个线程的PyPy-STM值得在PyPy上广泛运行。
在黑暗中作出选择
但愿这篇博客传达的不是一个总结, 而是一个关于生产力/性能折衷的方案。 Python已经清晰地拥有了强大的生产力辅助而且没有哪一个领域表现不佳,这还是我选择的语言。若是你发现本身有可能选择Python项目之外的东西,请必定要停下来思考没有使用Python所带来的生产力损失,而后看看你有各类选项让Python加快执行,这样你再去作一个全面的关于Python是否能够为你的项目工做的选择。python