摘要:鋪墊已了,進(jìn)入今天的正題,貓薦書系列之五高性能編程本書適合已入門還想要進(jìn)階和提高的讀者閱讀。書中列舉了兩個(gè)慘痛的教訓(xùn)華爾街公司騎士資本由于軟件升級(jí)引入的錯(cuò)誤,損失億美元公司小時(shí)全球中斷的嚴(yán)重事故。
稍微關(guān)心編程語言的使用趨勢(shì)的人都知道,最近幾年,國內(nèi)最火的兩種語言非 Python 與 Go 莫屬,于是,隔三差五就會(huì)有人問:這兩種語言誰更厲害/好找工作/高工資......
對(duì)于編程語言的爭論,就是猿界的生理周期,每個(gè)月都要鬧上一回。到了年末,各類榜單也是特別抓人眼球,鬧得更兇。
其實(shí),它們各有對(duì)方所無法比擬的優(yōu)勢(shì)以及用武之地,很多爭論都是沒有必要的。身為一個(gè)正在努力學(xué)習(xí) Python 的(準(zhǔn))中年程序員,我覺得吧,先把一門語言精進(jìn)了再說。沒有差勁的語言,只有差勁的程序員,等真的把語言學(xué)好了,必定是“山重水復(fù)疑無路,柳暗花明又一村”。
鋪墊已了,進(jìn)入今天的正題,Python 貓薦書系列之五——
本書適合已入門 Python、還想要進(jìn)階和提高的讀者閱讀。
所有計(jì)算機(jī)語言說到底都是在硬件層面的數(shù)據(jù)操作,所以高性能編程的一個(gè)終極目標(biāo)可以說是“高性能硬件編程”。然而,Python 是一門高度抽象的計(jì)算機(jī)語言,它的一大優(yōu)勢(shì)是開發(fā)團(tuán)隊(duì)的高效,不可否認(rèn)地存在這樣或那樣的設(shè)計(jì)缺陷,以及由于開發(fā)者的水平而造成的人為的性能缺陷。
本書的一大目的就是通過介紹各種模塊和原理,來促成在快速開發(fā) Python 的同時(shí)避免很多性能局限,既減低開發(fā)及維護(hù)成本,又收獲系統(tǒng)的高效。
1、性能分析是基礎(chǔ)首先的一個(gè)關(guān)鍵就是性能分析,借此可以找到性能的瓶頸,使得性能調(diào)優(yōu)做到事半功倍。
性能調(diào)優(yōu)能夠讓你的代碼能夠跑得“足夠快”以及“足夠瘦”。性能分析能夠讓你用最小的代價(jià)做出最實(shí)用的決定。
書中介紹了幾種性能分析的工具:
(1)基本技術(shù)如 IPython 的 %timeit 魔法函數(shù)、time.time()、以及一個(gè)計(jì)時(shí)修飾器,使用這些技術(shù)來了解語句和函數(shù)的行為。
(2)內(nèi)置工具如 cProfile,了解代碼中哪些函數(shù)耗時(shí)最長,并用 runsnake 進(jìn)行可視化。
(3)line_profiler 工具,對(duì)選定的函數(shù)進(jìn)行逐行分析,其結(jié)果包含每行被調(diào)用的次數(shù)以及每行花費(fèi)的時(shí)間百分比。
(4)memory_profiler 工具,以圖的形式展示RAM的使用情況隨時(shí)間的變化,解釋為什么某個(gè)函數(shù)占用了比預(yù)期更多的 RAM。
(5)Guppy 項(xiàng)目的 heapy 工具,查看 Python 堆中對(duì)象的數(shù)量以及每個(gè)對(duì)象的大小,這對(duì)于消滅奇怪的內(nèi)存泄漏特別有用。
(6)dowser 工具,通過Web瀏覽器界面審查一個(gè)持續(xù)運(yùn)行的進(jìn)程中的實(shí)時(shí)對(duì)象。
(7)dis 模塊,查看 CPython 的字節(jié)碼,了解基于棧的 Python 虛擬機(jī)如何運(yùn)行。
(8)單元測(cè)試,在性能分析時(shí)要避免由優(yōu)化手段帶來的破壞性后果。
作者強(qiáng)調(diào)了性能分析的重要性,同時(shí)也對(duì)如何確保性能分析的成功提了醒,例如,將測(cè)試代碼與主體代碼分離、避免硬件條件的干擾(如在BIOS上禁用了TurboBoost、禁用了操作系統(tǒng)改寫SpeedStep、只使用主電源等)、運(yùn)行實(shí)驗(yàn)時(shí)禁用后臺(tái)工具如備份和Dropbox、多次實(shí)驗(yàn)、重啟并重跑實(shí)驗(yàn)來二次驗(yàn)證結(jié)果,等等。
性能分析對(duì)于高性能編程的作用,就好比復(fù)雜度分析對(duì)于算法的作用,它本身不是高性能編程的一部分,但卻是最終有效的一種評(píng)判標(biāo)準(zhǔn)。
2、數(shù)據(jù)結(jié)構(gòu)的影響高性能編程最重要的事情是了解數(shù)據(jù)結(jié)構(gòu)所能提供的性能保證。
高性能編程的很大一部分是了解你查詢數(shù)據(jù)的方式,并選擇一個(gè)能夠迅速響應(yīng)這個(gè)查詢的數(shù)據(jù)結(jié)構(gòu)。
書中主要分析了 4 種數(shù)據(jù)結(jié)構(gòu):列表和元組就類似于其它編程語言的數(shù)組,主要用于存儲(chǔ)具有內(nèi)在次序的數(shù)據(jù);而字典和集合就類似其它編程語言的哈希表/散列集,主要用于存儲(chǔ)無序的數(shù)據(jù)。
本書在介紹相關(guān)內(nèi)容的時(shí)候很克制,所介紹的都是些影響“速度更快、開銷更低”的內(nèi)容,例如:內(nèi)置的 Tim 排序算法、列表的 resize 操作帶來的超額分配的開銷、元組的內(nèi)存滯留(intern機(jī)制)帶來的資源優(yōu)化、散列函數(shù)與嗅探函數(shù)的工作原理、散列碰撞帶來的麻煩與應(yīng)對(duì)、Python 命名空間的管理,等等。
理解了這些內(nèi)容,就能更加了解在什么情況下使用什么數(shù)據(jù)結(jié)構(gòu),以及如何優(yōu)化這些數(shù)據(jù)結(jié)構(gòu)的性能。
另外,關(guān)于這 4 種數(shù)據(jù)結(jié)構(gòu),書中還得出了一些有趣的結(jié)論:對(duì)于一個(gè)擁有100 000 000個(gè)元素的大列表,實(shí)際分配的可能是112 500 007個(gè)元素;初始化一個(gè)列表比初始化一個(gè)元組慢5.1 倍;字典或集合默認(rèn)的最小長度是8(也就是說,即使你只保存3個(gè)值,Python仍然會(huì)分配 8 個(gè)元素)、對(duì)于有限大小的字典不存在一個(gè)最佳的散列函數(shù)。
3、矩陣和矢量計(jì)算矢量計(jì)算是計(jì)算機(jī)工作原理不可或缺的部分,也是在芯片層次上對(duì)程序進(jìn)行加速所必須了解的部分。
然而,原生 Python 并不支持矢量操作,因?yàn)?Python 列表存儲(chǔ)的不是實(shí)際的數(shù)據(jù),而是對(duì)實(shí)際數(shù)據(jù)的引用。在矢量和矩陣操作時(shí),這種存儲(chǔ)結(jié)構(gòu)會(huì)造成極大的性能下降。比如,grid[5][2] 中的兩個(gè)數(shù)字其實(shí)是索引值,程序需要根據(jù)索引值進(jìn)行兩次查找,才能獲得實(shí)際的數(shù)據(jù)。
同時(shí),因?yàn)閿?shù)據(jù)被分片存儲(chǔ),我們只能分別對(duì)每一片進(jìn)行傳輸,而不是一次性傳輸整個(gè)塊,因此,內(nèi)存?zhèn)鬏數(shù)拈_銷也很大。
減少瓶頸最好的方法是讓代碼知道如何分配我們的內(nèi)存以及如何使用我們的數(shù)據(jù)進(jìn)行計(jì)算。
Numpy 能夠?qū)?shù)據(jù)連續(xù)存儲(chǔ)在內(nèi)存中并支持?jǐn)?shù)據(jù)的矢量操作,在數(shù)據(jù)處理方面,它是高性能編程的最佳解決方案之一。
Numpy 帶來性能提升的關(guān)鍵在于,它使用了高度優(yōu)化且特殊構(gòu)建的對(duì)象,取代了通用的列表結(jié)構(gòu)來處理數(shù)組,由此減少了內(nèi)存碎片;此外,自動(dòng)矢量化的數(shù)學(xué)操作使得矩陣計(jì)算非常高效。
Numpy 在矢量操作上的缺陷是一次只能處理一個(gè)操作。例如,當(dāng)我們做 A B + C 這樣的矢量操作時(shí),先要等待 A B 操作完成,并保存數(shù)據(jù)在一個(gè)臨時(shí)矢量中,然后再將這個(gè)新的矢量和 C 相加。
Numexpr 模塊可以將矢量表達(dá)式編譯成非常高效的代碼,可以將緩存失效以及臨時(shí)變量的數(shù)量最小化。另外,它還能利用多核 CPU 以及 Intel 芯片專用的指令集來將速度最大化。
書中嘗試了多種優(yōu)化方法的組合,通過詳細(xì)的分析,展示了高性能編程所能帶來的性能提升效果。
4、編譯器書中提出一個(gè)觀點(diǎn):讓你的代碼運(yùn)行更快的最簡單的辦法就是讓它做更少的工作。
編譯器把代碼編譯成機(jī)器碼,是提高性能的關(guān)鍵組成部分。
不同的編譯器有什么優(yōu)勢(shì)呢,它們對(duì)于性能提升會(huì)帶來多少好處呢?書中主要介紹了如下編譯工具:
Cython ——這是編譯成C最通用的工具,覆蓋了Numpy和普通的Python代碼(需要一些C語言的知識(shí))。
Shed Skin —— 一個(gè)用于非Numpy代碼的,自動(dòng)把Python轉(zhuǎn)換成C的轉(zhuǎn)換器。
Numba —— 一個(gè)專用于Numpy代碼的新編譯器。
Pythran —— 一個(gè)用于Numpy和非numpy代碼的新編譯器。
PyPy —— 一個(gè)用于非Numpy代碼的,取代常規(guī)Python可執(zhí)行程序的穩(wěn)定的即時(shí)編譯器。
書中分析了這幾種編譯器的工作原理、優(yōu)化范圍、以及適用場景等,是不錯(cuò)的入門介紹。此外,作者還提到了其它的編譯工具,如Theano、Parakeet、PyViennaCL、ViennaCL、Nuitka 與 Pyston 等,它們各有取舍,在不同領(lǐng)域提供了支撐之力。
5、密集型任務(wù)高性能編程的一個(gè)改進(jìn)方向是提高密集型任務(wù)的處理效率,而這樣的任務(wù)無非兩大類:I/O 密集型與 CPU 密集型。
I/O 密集型任務(wù)主要是磁盤讀寫與網(wǎng)絡(luò)通信任務(wù),占用較多 I/O 時(shí)間,而對(duì) CPU 要求較少;CPU 密集型任務(wù)恰恰相反,它們要消耗較多的 CPU 時(shí)間,進(jìn)行大量的復(fù)雜的計(jì)算,例如計(jì)算圓周率與解析視頻等。
改善 I/O 密集型任務(wù)的技術(shù)是異步編程 ,它使得程序在 I/O 阻塞時(shí),并發(fā)執(zhí)行其它任務(wù),并通過“事件循環(huán)”機(jī)制來管理各項(xiàng)任務(wù)的運(yùn)行時(shí)機(jī),從而提升程序的執(zhí)行效率。
書中介紹了三種異步編程的庫:Gevent、Tornado 和 Asyncio,對(duì)三種模塊的區(qū)別做了較多分析。
改善 CPU 密集型任務(wù)的主要方法是利用多核 CPU 進(jìn)行多進(jìn)程的運(yùn)算。
Multiprocessing 模塊使用基于進(jìn)程和基于線程的并行處理,在隊(duì)列上共享任務(wù),以及在進(jìn)程間共享數(shù)據(jù),是處理 CPU 密集型任務(wù)的重要技術(shù)。
書中沒有隱瞞它的局限性:Amdahl 定律揭示的優(yōu)化限度、適應(yīng)于單機(jī)多核而多機(jī)則有其它選擇、全局解釋鎖 GIL 的束縛、以及進(jìn)程間通信(同步數(shù)據(jù)和檢查共享數(shù)據(jù))的開銷。針對(duì)進(jìn)程間通信問題,書中還分析了多種解決方案,例如 Less Na?ve Pool、Manager、Redis、RawValue、MMap 等。
6、集群與現(xiàn)場教訓(xùn)集群是一種多服務(wù)器運(yùn)行相同任務(wù)的結(jié)構(gòu),也就是說,集群中的各節(jié)點(diǎn)提供相同的服務(wù),其優(yōu)點(diǎn)是系統(tǒng)擴(kuò)展容易、具備容災(zāi)恢復(fù)能力。
集群需要克服的挑戰(zhàn)有:機(jī)器間信息同步的延遲、機(jī)器間配置與性能的差異、機(jī)器的損耗與維護(hù)、其它難以預(yù)料的問題。書中列舉了兩個(gè)慘痛的教訓(xùn):華爾街公司騎士資本由于軟件升級(jí)引入的錯(cuò)誤,損失4.62億美元;Skype 公司 24 小時(shí)全球中斷的嚴(yán)重事故。
書中給我們重點(diǎn)介紹了三個(gè)集群化解決方案:Parallel Python、IPython Parallel 和 NSQ。引申也介紹了一些普遍使用的方案,如 Celery、Gearman、PyRes、SQS。
關(guān)于現(xiàn)場教訓(xùn),它們不僅僅是一些事故或者故事而已,由成功的公司所總結(jié)出來的經(jīng)驗(yàn)更是來之不易的智慧。書中多帶帶用一章內(nèi)容分享了六篇文章,這些文章出自幾個(gè)使用 Python 的公司/大型組織,像是Adaptive Lab、RadimRehurek、Smesh、PyPy 與 Lanyrd ,這些國外組織的一線實(shí)踐經(jīng)驗(yàn),應(yīng)該也能給國內(nèi)的 Python 社區(qū)帶來一些啟示。
7、寫在最后眾所周知,Python 應(yīng)用前景大、簡單易學(xué)、方便開發(fā)與部署,然而與其它編程語言相比,它的性能幾乎總是落于下風(fēng)。如何解決這個(gè)難題呢?本期薦書的書目就是一種回應(yīng)。
《Python高性能編程》全書從微觀到宏觀對(duì)高性能編程的方方面面做了講解,主要包含以下主題:計(jì)算機(jī)內(nèi)部結(jié)構(gòu)的背景知識(shí)、列表和元組、字典和集合、迭代器和生成器、矩陣和矢量計(jì)算、編譯器、并發(fā)、集群和工作隊(duì)列等。這些內(nèi)容為編寫更快的 Python 指明了答案。
本篇文章主要以梳理書中的內(nèi)容要點(diǎn)為主,平均而兼顧地理清了全書脈絡(luò)(PS:介紹得太面面俱到了,但愿不被指責(zé)為一篇流水賬的讀書筆記才好......)。我認(rèn)為,鑒于書中談及的這些話題,它就足以成為我們薦書欄目的一員了。除去某些句段的糟糕翻譯、成書時(shí)間比較早(2014年)而造成的過時(shí)外,這本書總體質(zhì)量不錯(cuò),可稱為是一份優(yōu)秀的高性能編程的指引手冊(cè)。
關(guān)于薦書欄目,我最后多說幾句。本欄目原計(jì)劃兩周左右出一篇,但由于其它系列文章花費(fèi)了我不少時(shí)間,而要寫好一篇薦書/書評(píng)也特別費(fèi)勁,最后生生造成了現(xiàn)在兩月一更的尷尬局面......這篇文章是個(gè)錯(cuò)誤的示范,我不該試圖全面通讀與概括其內(nèi)容的。因此,我決定今后選一些易讀的書目,在寫作上也盡量走短小精悍風(fēng),希望能持續(xù)地將本欄目運(yùn)作下去。若你有什么建議(如書目推薦、書評(píng)推薦、寫作建議、甚至是投稿),我隨時(shí)歡迎,先行致謝啦。
往期薦書回顧:
第一期:《編寫高質(zhì)量代碼改善 Python 程序的 91 個(gè)建議》
第二期:《Python最佳實(shí)踐指南》
第三期:《黑客與畫家》
第四期:《Python源碼剖析》
-----------------
本文原創(chuàng)并首發(fā)于微信公眾號(hào)【Python貓】,后臺(tái)回復(fù)“愛學(xué)習(xí)”,免費(fèi)獲得20+本精選電子書。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/19462.html
摘要:鋪墊已了,進(jìn)入今天的正題,貓薦書系列之五高性能編程本書適合已入門還想要進(jìn)階和提高的讀者閱讀。書中列舉了兩個(gè)慘痛的教訓(xùn)華爾街公司騎士資本由于軟件升級(jí)引入的錯(cuò)誤,損失億美元公司小時(shí)全球中斷的嚴(yán)重事故。 showImg(https://segmentfault.com/img/bVbm92w?w=6720&h=4480); 稍微關(guān)心編程語言的使用趨勢(shì)的人都知道,最近幾年,國內(nèi)最火的兩種語言非...
摘要:本期貓薦書欄目系列之六,就以此為話題,推薦給大家兩本書它們都叫深度學(xué)習(xí),但是內(nèi)容很不一樣。事實(shí)上,第一本書被很多人譽(yù)為深度學(xué)習(xí)的圣經(jīng),知名度極高,有一個(gè)昵稱叫作花書。 最近出了兩件大新聞,相信大家可能有所耳聞。 我來當(dāng)個(gè)播報(bào)員,給大家轉(zhuǎn)述一下: 1、中國隊(duì)在第 11 界羅馬尼亞數(shù)學(xué)大師賽(RMM)中無緣金牌。該項(xiàng)賽事是三大國際賽事之一,被譽(yù)為中學(xué)奧數(shù)的最高難度。其中一道題,令中國隊(duì)全軍...
閱讀 1860·2021-11-15 11:39
閱讀 1226·2021-10-18 13:29
閱讀 1187·2021-08-31 09:42
閱讀 2741·2019-08-30 11:11
閱讀 2116·2019-08-26 12:12
閱讀 2115·2019-08-26 10:17
閱讀 3391·2019-08-23 18:38
閱讀 3228·2019-08-23 18:38