稍微关心一下编程语言使用趋势的人都知道,近年来国内最流行的两种语言是Python和Go。有人问:这两种语言哪个更厉害/好找工作/薪水高……编程语言之争是猿界的生理循环,每个月都会吵架。岁末年关,各类榜单也格外惹眼,喧嚣之声更甚。其实,它们各有各的优势和用途,很多争论都是多余的。作为一个正在尝试学习Python的(准)中年程序员,我想,还是先完善一门语言吧。没有不好的语言,只有不好的程序员。真正学好语文的时候,一定是“山重水复疑,万里无路,柳暗花明又一村”。铺垫完毕,让我们进入今天的主题,Python猫推荐书籍系列之五——
Python高性能编程本书适合已经入门Python,想要进阶提升的读者。归根结底,所有的计算机语言都是硬件层面的数据操作,所以高性能编程的一个最终目标可以说是“高性能硬件编程”。然而,Python是一种高度抽象的计算机语言。它的优势之一是开发团队的高效率。不可否认,其中存在这样或那样的设计缺陷,以及开发人员水平造成的人为性能缺陷。本书的主要目的之一是通过介绍各种模块和原理,促进Python的快速发展,同时避免许多性能限制,既降低了开发和维护成本,又获得了系统效率。1、性能分析是基础。第一个关键是性能分析,找到性能瓶颈,进行性能调优可以达到事半功倍的效果。性能调优可以让你的代码运行起来“足够快”和“足够精简”。性能分析可以让您以最少的努力做出最实际的决策。本书介绍了几种性能分析工具:(1)IPython的%timeit魔术函数、time.time()和计时装饰器等基本技术,使用这些技术来理解语句和函数的行为。(2)内置cProfile等工具,了解代码中哪些函数耗时最长,用runsnake可视化。(3)line_profiler工具逐行分析选中的函数,结果包括每行被调用的次数和每行所花费时间的百分比。(4)memory_profiler工具,以图表的形式展示RAM使用量随时间的变化,并解释为什么某个函数占用的RAM比预期的多。(5)Guppy项目的heapy工具,查看Python堆中对象的数量和每个对象的大小,对于排除奇怪的内存泄漏特别有用。(6)dowser工具,它通过Web浏览器界面检查连续运行过程中的实时对象。(7)dis模块,查看CPython的字节码,了解基于栈的Python虚拟机是如何运行的。(8)单元测试,避免性能分析时采用优化手段带来的破坏性后果。作者在强调profiling的重要性的同时,也提醒了如何保证profiling的成功,比如将测试代码和主代码分离,避免硬件条件的干扰(比如在BIOS上禁用TurboBoost,禁用操作系统OverrideSpeedStep,仅使用电源等),在禁用备份和Dropbox等后台工具的情况下运行实验,多次运行实验,重新启动并重新运行实验以仔细检查结果等。性能??分析对于高性能编程的作用就像复杂性分析对算法的作用。它本身并不是高性能编程的一部分,但它是一个最终有效的标准。2、数据结构的影响高性能编程中最重要的是理解数据结构所能提供的性能保证。高性能编程的很大一部分是了解您如何查询数据,并选择可以快速响应该查询的数据结构。本书主要分析了4种数据结构:列表和元组类似于其他编程语言中的数组,主要用于存储具有固有顺序的数据;字典和集合类似于其他编程语言中的哈希表/哈希集,主要用于存储无序数据。这本书在介绍相关内容时非常克制,介绍的都是影响“更快速度和更低开销”的内容,比如:内置的Tim排序算法,list的resize操作带来的overallocation开销,Resource元组的内存保留(intern机制)带来的优化,hash函数和嗅探函数的工作原理,hash冲突带来的麻烦和解决方案,Python命名空间的管理等。了解这些,可以更好的理解什么数据结构在什么情况下使用,以及如何优化这些数据结构的性能。此外,关于这4种数据结构,书中还得出了一些有趣的结论:对于一个拥有1亿个元素的大列表,实际分配可能是112500007个元素;组慢5.1倍;字典或集合的默认最小长度为8(也就是说,即使你只存储3个值,Python仍会分配8个元素),没有一个适合有限大小字典的最佳哈希函数。3、矩阵和向量计算向量计算是计算机工作原理中不可或缺的部分,也是在芯片级加速程序必须了解的部分。但是Python原生不支持向量运算,因为Python列表存储的不是实际数据,而是实际数据的引用。在向量和矩阵运算中,这种存储结构会造成巨大的性能下降。比如grid[5][2]中的两个数字其实就是索引值,程序需要根据索引值进行两次查找才能得到实际的数据。同时,由于数据是分块存储的,我们只能分块传输,不能一次性传输整个块。因此,内存传输的开销也很大。减少瓶颈的最好方法是让代码知道如何分配我们的内存以及如何使用我们的数据进行计算。Numpy能够在内存中连续存储数据,并支持对数据进行向量运算,使其成为高性能编程在数据处理方面的最佳解决方案之一。Numpy性能提升的关键是它使用高度优化和特殊构造的对象来处理数组,而不是通用的列表结构,从而减少内存碎片;此外,数学运算的自动矢量化使得矩阵计算非常高效。Numpy向量运算的缺陷在于它一次只能处理一个运算。比如我们在做AB+C这样的向量运算时,首先要等待AB运算完成,并将数据保存在一个临时向量中,然后将这个新的向量添加到C中。Numexpr模块编译向量表达式变成非常有效的代码,最大限度地减少缓存失效和临时变量的数量。此外,它还可以利用多核CPU和英特尔芯片专用指令集来最大限度地提高速度。书中尝试了各种优化方法的组合,并通过详细的分析展示了高性能编程所能带来的性能提升效果。4.编译器书中提出的一点:让你的代码运行得更快的最简单方法是让它做更少的工作。编译器将代码编译成机器代码,是提高性能的关键组件。不同编译器的优点是什么,它们对性能有多大好处?本书主要介绍以下编译工具:Cython——这是最常用的编译成C的工具,涵盖了Numpy和普通的Python代码(需要一定的C语言知识)。ShedSkin-用于非Numpy代码的自动Python-to-C转换器.Numba-专用于Numpy代码的新编译器。Pythran-用于Numpy和非numpy代码的新编译器。PyPy-一种用于非Numpy代码的稳定即时编译器,可替代常规Python可执行文件。书中分析了这几种编译器的工作原理、优化范围、适用场景,很好的介绍。此外,作者还提到了其他的编译工具,如Theano、Parakeet、PyViennaCL、ViennaCL、Nuitka和Pyston等,它们各有所长,在不同领域提供支持。5、密集型任务高性能编程的一个改进方向是提高密集型任务的处理效率,这类任务无非是两大类:I/O密集型和CPU密集型。I/O密集型任务主要是磁盘读写和网络通信任务,占用I/O时间较多,需要CPU较少;相反,CPU密集型任务消耗更多的CPU时间并执行大量复杂的计算,例如计算pi和分析视频等。改善I/O密集型任务的技术是异步编程,它使程序能够在I/O阻塞时并发执行其他任务,通过“事件循环”机制管理各个任务的运行时机,从而提高程序的执行效率。书中介绍了三个异步编程库:Gevent、Tornado、Asyncio,并对这三个模块的区别做了很多分析。改善CPU密集型任务的主要方法是利用多核CPU进行多处理操作。Multiprocessing模块使用基于进程和基于线程的并行处理,在队列上共享任务,在进程间共享数据,这些都是处理CPU密集型任务的重要技术。它的局限性在书中没有隐藏:Amdahl定律揭示的优化限制,适应单机多核而多机有其他选择,全局解释器锁(GIL)的约束,以及进程间通信的开销(同步数据和检查共享数据)。对于进程间通信问题,书中也分析了多种解决方案,如LessNa?vePool、Manager、Redis、RawValue、MMap等。6.集群及现场经验集群是一种多台服务器运行的结构相同的任务,即集群中的每个节点提供相同的服务,其优点是易于系统扩展和容灾能力。集群需要克服的挑战包括:机器间信息同步延迟、机器间配置和性能差异、机器丢失和维护等不可预知的问题。书中列出了两个惨痛的教训:华尔街公司KnightCapital由于软件升级引入的错误损失了4.62亿美元;Skype的24小时全球中断是一次严重的事故。本书为我们重点介绍了三种集群解决方案:ParallelPython、IPythonParallel和NSQ。该扩展还介绍了一些常用的解决方案,例如Celery、Gearman、PyRes、SQS。关于实地的教训,不只是一些意外或故事,而是成功企业总结出来的经验,是来之不易的智慧。本书用单独的章节来分享六篇文章。这些文章来自几家使用Python的公司/大型组织,例如AdaptiveLab、RadimRehurek、Smesh、PyPy和Lanyrd。这些国外机构的一线实践经验,应该也能给国内的Python社区带来一些启发。7、写在最后众所周知,Python应用前景广阔,简单易学,开发部署方便。然而,与其他编程语言相比,它的性能几乎总是处于劣势。如何解决这个问题呢?本期推荐书目书目即是回应。《Python高性能编程》本书从微观到宏观全面讲解了高性能编程,主要包括以下主题:计算机内部结构背景知识、列表和元组、字典和集合、迭代器和生成器、矩阵和向量计算、编译器、并发、集群、工作队列等。这些指向编写更快Python的答案。这篇文章主要是对书中内容的要点进行梳理,把全书的来龙去脉理清(PS:介绍太全面了,希望不要被骂读书笔记的日记……)。我认为,考虑到它涉及的主题,它足以包含在我们的推荐书籍专栏中。除了部分句子翻译不好,写作时间较早(2014年)造成的过时,本书整体质量不错,堪称高性能编程的优秀指南。关于推荐书栏目,最后再多说几句。这个专栏本来打算两周左右发一篇,但是因为其他系列的文章占用了我很多时间,写推荐书/书评也很费力,最后导致尴尬的是每两个月更新一次。.....这篇文章是一个虚假的演示,我不应该试图通读和概括它的内容。因此,我决定以后选择一些通俗易懂的参考书目,写作上尽量做到短小精悍,希望能继续经营这个栏目。如果您有任何建议(例如书目推荐、书评推荐、写作建议,甚至投稿),我随时欢迎他们,在此先致谢。回顾往期书籍推荐:Issue1:《编写高质量代码改善 Python 程序的 91 个建议》Issue2:《Python最佳实践指南》Issue3:《黑客与画家》Issue4:《Python源码剖析》-----------------这篇文章是原发于微信公众号【Python猫】,后台回复“爱学习”,送20+精选电子书。