新聞中心
- 為犧牲性能追求生產(chǎn)率而吶喊
讓我從關(guān)于 Python 中的 asyncio 這個標(biāo)準(zhǔn)庫的討論中休息一會,談?wù)勎易罱谒伎嫉囊恍〇|西:Python 的速度。對不了解我的人說明一下,我是一個 Python 的粉絲,而且我在我能想到的所有地方都積極地使用 Python。人們對 Python ***的抱怨之一就是它的速度比較慢,有些人甚至拒絕嘗試使用 Python,因?yàn)樗绕渌Z言速度慢。這里說說為什么我認(rèn)為應(yīng)該嘗試使用 Python,盡管它是有點(diǎn)慢。

在吉安等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、做網(wǎng)站 網(wǎng)站設(shè)計制作按需定制開發(fā),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站設(shè)計,全網(wǎng)整合營銷推廣,外貿(mào)網(wǎng)站建設(shè),吉安網(wǎng)站建設(shè)費(fèi)用合理。
速度不再重要
過去的情形是,程序需要花費(fèi)很長的時間來運(yùn)行,CPU 比較貴,內(nèi)存也很貴。程序的運(yùn)行時間是一個很重要的指標(biāo)。計算機(jī)非常的昂貴,計算機(jī)運(yùn)行所需要的電也是相當(dāng)貴的。對這些資源進(jìn)行優(yōu)化是因?yàn)橐粋€永恒的商業(yè)法則:
- 優(yōu)化你最貴的資源。
在過去,最貴的資源是計算機(jī)的運(yùn)行時間。這就是導(dǎo)致計算機(jī)科學(xué)致力于研究不同算法的效率的原因。然而,這已經(jīng)不再是正確的,因?yàn)楝F(xiàn)在硅芯片很便宜,確實(shí)很便宜。運(yùn)行時間不再是你最貴的資源。公司最貴的資源現(xiàn)在是它的員工時間。或者換句話說,就是你。把事情做完比把它變快更加重要。實(shí)際上,這是相當(dāng)?shù)闹匾?,我將把它再次放在這里,仿佛它是一個引文一樣(給那些只是粗略瀏覽的人):
- 把事情做完比快速地做事更加重要。
你可能會說:“我的公司在意速度,我開發(fā)一個 web 應(yīng)用程序,那么所有的響應(yīng)時間必須少于 x 毫秒?!被蛘撸拔覀兪チ丝蛻?,因?yàn)樗麄冋J(rèn)為我們的 app 運(yùn)行太慢了?!蔽也⒉皇窍胝f速度一點(diǎn)也不重要,我只是想說速度不再是最重要的東西;它不再是你最貴的資源。
速度是唯一重要的東西
當(dāng)你在編程的背景下說 速度 時,你通常是說性能,也就是 CPU 周期。當(dāng)你的 CEO 在編程的背景下說 速度 時,他指的是業(yè)務(wù)速度,最重要的指標(biāo)是產(chǎn)品上市的時間。基本上,你的產(chǎn)品/web 程序是多么的快并不重要。它是用什么語言寫的也不重要。甚至它需要花費(fèi)多少錢也不重要。在一天結(jié)束時,讓你的公司存活下來或者死去的唯一事物就是產(chǎn)品上市時間。我不只是說創(chuàng)業(yè)公司的想法 -- 你開始賺錢需要花費(fèi)多久,更多的是“從想法到客戶手中”的時間期限。企業(yè)能夠存活下來的唯一方法就是比你的競爭對手更快地創(chuàng)新。如果在你的產(chǎn)品上市之前,你的競爭對手已經(jīng)提前上市了,那么你想出了多少好的主意也將不再重要。你必須***個上市,或者至少能跟上。一但你放慢了腳步,你就輸了。
- 企業(yè)能夠存活下來的唯一方法就是比你的競爭對手更快地創(chuàng)新。
一個微服務(wù)的案例
像 Amazon、Google 和 Netflix 這樣的公司明白快速前進(jìn)的重要性。他們創(chuàng)建了一個業(yè)務(wù)系統(tǒng),可以使用這個系統(tǒng)迅速地前進(jìn)和快速的創(chuàng)新。微服務(wù)是針對他們的問題的解決方案。這篇文章不談你是否應(yīng)該使用微服務(wù),但是至少要理解為什么 Amazon 和 Google 認(rèn)為他們應(yīng)該使用微服務(wù)。
微服務(wù)本來就很慢。微服務(wù)的主要概念是用網(wǎng)絡(luò)調(diào)用來打破邊界。這意味著你正在把使用的函數(shù)調(diào)用(幾個 cpu 周期)轉(zhuǎn)變?yōu)橐粋€網(wǎng)絡(luò)調(diào)用。沒有什么比這更影響性能了。和 CPU 相比較,網(wǎng)絡(luò)調(diào)用真的很慢。但是這些大公司仍然選擇使用微服務(wù)。我所知道的架構(gòu)里面沒有比微服務(wù)還要慢的了。微服務(wù)***的弊端就是它的性能,但是***的長處就是上市的時間。通過在較小的項(xiàng)目和代碼庫上建立團(tuán)隊(duì),一個公司能夠以更快的速度進(jìn)行迭代和創(chuàng)新。這恰恰表明了,非常大的公司也很在意上市時間,而不僅僅只是只有創(chuàng)業(yè)公司。
CPU 不是你的瓶頸
如果你在寫一個網(wǎng)絡(luò)應(yīng)用程序,如 web 服務(wù)器,很有可能的情況會是,CPU 時間并不是你的程序的瓶頸。當(dāng)你的 web 服務(wù)器處理一個請求時,可能會進(jìn)行幾次網(wǎng)絡(luò)調(diào)用,例如到數(shù)據(jù)庫,或者像 Redis 這樣的緩存服務(wù)器。雖然這些服務(wù)本身可能比較快速,但是對它們的網(wǎng)絡(luò)調(diào)用卻很慢。這里有一篇很好的關(guān)于特定操作的速度差異的博客文章。在這篇文章里,作者把 CPU 周期時間縮放到更容易理解的人類時間。如果一個單獨(dú)的 CPU 周期等同于 1 秒,那么一個從 California 到 New York 的網(wǎng)絡(luò)調(diào)用將相當(dāng)于 4 年。那就說明了網(wǎng)絡(luò)調(diào)用是多少的慢。按一些粗略估計,我們可以假設(shè)在同一數(shù)據(jù)中心內(nèi)的普通網(wǎng)絡(luò)調(diào)用大約需要 3 毫秒。這相當(dāng)于我們“人類比例” 3 個月?,F(xiàn)在假設(shè)你的程序是高 CPU 密集型,這需要 100000 個 CPU 周期來對單一調(diào)用進(jìn)行響應(yīng)。這相當(dāng)于剛剛超過 1 天?,F(xiàn)在讓我們假設(shè)你使用的是一種要慢 5 倍的語言,這將需要大約 5 天。很好,將那與我們 3 個月的網(wǎng)絡(luò)調(diào)用時間相比,4 天的差異就顯得并不是很重要了。如果有人為了一個包裹不得不至少等待 3 個月,我不認(rèn)為額外的 4 天對他們來說真的很重要。
上面所說的***意思是,盡管 Python 速度慢,但是這并不重要。語言的速度(或者 CPU 時間)幾乎從來不是問題。實(shí)際上谷歌曾經(jīng)就這一概念做過一個研究,并且他們就此發(fā)表過一篇論文。那篇論文論述了設(shè)計高吞吐量的系統(tǒng)。在結(jié)論里,他們說到:
在高吞吐量的環(huán)境中使用解釋性語言似乎是矛盾的,但是我們已經(jīng)發(fā)現(xiàn) CPU 時間幾乎不是限制因素;語言的表達(dá)性是指,大多數(shù)程序是源程序,同時它們的大多數(shù)時間花費(fèi)在 I/O 讀寫和本機(jī)的運(yùn)行時代碼上。而且,解釋性語言無論是在語言層面的輕松實(shí)驗(yàn)還是在允許我們在很多機(jī)器上探索分布計算的方法都是很有幫助的,
再次強(qiáng)調(diào):
- CPU 時間幾乎不是限制因素。
如果 CPU 時間是一個問題怎么辦?
你可能會說,“前面說的情況真是太好了,但是我們確實(shí)有過一些問題,這些問題中 CPU 成為了我們的瓶頸,并造成了我們的 web 應(yīng)用的速度十分緩慢”,或者“在服務(wù)器上 X 語言比 Y 語言需要更少的硬件資源來運(yùn)行?!边@些都可能是對的。關(guān)于 web 服務(wù)器有這樣的美妙的事情:你可以幾乎***地負(fù)載均衡它們。換句話說,可以在 web 服務(wù)器上投入更多的硬件。當(dāng)然,Python 可能會比其他語言要求更好的硬件資源,比如 c 語言。只是把硬件投入在 CPU 問題上。相比于你的時間,硬件就顯得非常的便宜了。如果你在一年內(nèi)節(jié)省了兩周的生產(chǎn)力時間,那將遠(yuǎn)遠(yuǎn)多于所增加的硬件開銷的回報。
那么,Python 更快一些嗎?
這一篇文章里面,我一直在談?wù)撟钪匾氖情_發(fā)時間。所以問題依然存在:當(dāng)就開發(fā)時間而言,Python 要比其他語言更快嗎?按常規(guī)慣例來看,我、google 還有其他幾個人可以告訴你 Python 是多么的高效。它為你抽象出很多東西,幫助你關(guān)注那些你真正應(yīng)該編寫代碼的地方,而不會被困在瑣碎事情的雜草里,比如你是否應(yīng)該使用一個向量或者一個數(shù)組。但你可能不喜歡只是聽別人說的這些話,所以讓我們來看一些更多的經(jīng)驗(yàn)數(shù)據(jù)。
在大多數(shù)情況下,關(guān)于 python 是否是更高效語言的爭論可以歸結(jié)為腳本語言(或動態(tài)語言)與靜態(tài)類型語言兩者的爭論。我認(rèn)為人們普遍接受的是靜態(tài)類型語言的生產(chǎn)力較低,但是,這有一篇優(yōu)秀的論文解釋了為什么不是這樣。就 Python 而言,這里有一項(xiàng)研究,它調(diào)查了不同語言編寫字符串處理的代碼所需要花費(fèi)的時間,供參考。
在上述研究中,Python 的效率比 Java 高出 2 倍。有一些其他研究也顯示相似的東西。 Rosetta Code 對編程語言的差異進(jìn)行了深入的研究。在論文中,他們把 python 與其他腳本語言/解釋性語言相比較,得出結(jié)論:
- Python 更簡潔,即使與函數(shù)式語言相比較(平均要短 1.2 到 1.6 倍)
普遍的趨勢似乎是 Python 中的代碼行總是更少。代碼行聽起來可能像一個可怕的指標(biāo),但是包括上面已經(jīng)提到的兩項(xiàng)研究在內(nèi)的多項(xiàng)研究表明,每種語言中每行代碼所需要花費(fèi)的時間大約是一樣的。因此,限制代碼行數(shù)就可以提高生產(chǎn)效率。甚至 codinghorror(一名 C# 程序員)本人寫了一篇關(guān)于 Python 是如何更有效率的文章。
我認(rèn)為說 Python 比其他的很多語言更加的有效率是公正的。這主要是由于 Python 有大量的自帶以及第三方庫。如果你不知道為何 Python 是如此的小巧和高效,我邀請你借此機(jī)會學(xué)習(xí)一點(diǎn) python,自己多實(shí)踐。這兒是你的***個程序:
- import __hello__
但是如果速度真的重要呢?
上述論點(diǎn)的語氣可能會讓人覺得優(yōu)化與速度一點(diǎn)也不重要。但事實(shí)是,很多時候運(yùn)行時性能真的很重要。一個例子是,你有一個 web 應(yīng)用程序,其中有一個特定的端點(diǎn)需要用很長的時間來響應(yīng)。你知道這個程序需要多快,并且知道程序需要改進(jìn)多少。
在我們的例子中,發(fā)生了兩件事:
- 我們注意到有一個端點(diǎn)執(zhí)行緩慢。
- 我們承認(rèn)它是緩慢,因?yàn)槲覀冇幸粋€可以衡量是否足夠快的標(biāo)準(zhǔn),而它沒達(dá)到那個標(biāo)準(zhǔn)。
我們不必在應(yīng)用程序中微調(diào)優(yōu)化所有內(nèi)容,只需要讓其中每一個都“足夠快”。如果一個端點(diǎn)花費(fèi)了幾秒鐘來響應(yīng),你的用戶可能會注意到,但是,他們并不會注意到你將響應(yīng)時間由 35 毫秒降低到 25 毫秒?!白銐蚝谩本褪悄阈枰龅降乃惺虑?。免責(zé)聲明: 我應(yīng)該說有一些應(yīng)用程序,如實(shí)時投標(biāo)程序,確實(shí)需要細(xì)微優(yōu)化,每一毫秒都相當(dāng)重要。但那只是例外,而不是規(guī)則。
為了明白如何對端點(diǎn)進(jìn)行優(yōu)化,你的***步將是配置代碼,并嘗試找出瓶頸在哪。畢竟:
- 任何除了瓶頸之外的改進(jìn)都是錯覺。Any improvements made anywhere besides the bottleneck are an illusion. -- Gene Kim
如果你的優(yōu)化沒有觸及到瓶頸,你只是浪費(fèi)你的時間,并沒有解決實(shí)際問題。在你優(yōu)化瓶頸之前,你不會得到任何重要的改進(jìn)。如果你在不知道瓶頸是什么前就嘗試優(yōu)化,那么你最終只會在部分代碼中玩耍。在測量和確定瓶頸之前優(yōu)化代碼被稱為“過早優(yōu)化”。人們常提及 Donald Knuth 說的話,但他聲稱這句話實(shí)際上是他從別人那里聽來的:
- 過早優(yōu)化是萬惡之源Premature optimization is the root of all evil。
在談到維護(hù)代碼庫時,來自 Donald Knuth 的更完整的引文是:
- 在 97% 的時間里,我們應(yīng)該忘記微不足道的效率:過早的優(yōu)化是萬惡之源。然而在關(guān) 鍵的 3%,我們不應(yīng)該錯過優(yōu)化的機(jī)會。 —— Donald Knuth
換句話說,他所說的是,在大多數(shù)時間你應(yīng)該忘記對你的代碼進(jìn)行優(yōu)化。它幾乎總是足夠好。在不是足夠好的情況下,我們通常只需要觸及 3% 的代碼路徑。比如因?yàn)槟闶褂昧?if 語句而不是函數(shù),你的端點(diǎn)快了幾納秒,但這并不會使你贏得任何獎項(xiàng)。
過早的優(yōu)化包括調(diào)用某些更快的函數(shù),或者甚至使用特定的數(shù)據(jù)結(jié)構(gòu),因?yàn)樗ǔ8?。計算機(jī)科學(xué)認(rèn)為,如果一個方法或者算法與另一個具有相同的漸近增長(或稱為 Big-O),那么它們是等價的,即使在實(shí)踐中要慢兩倍。計算機(jī)是如此之快,算法隨著數(shù)據(jù)/使用增加而造成的計算增長遠(yuǎn)遠(yuǎn)超過實(shí)際速度本身。換句話說,如果你有兩個 O(log n) 的函數(shù),但是一個要慢兩倍,這實(shí)際上并不重要。隨著數(shù)據(jù)規(guī)模的增大,它們都以同樣的速度“慢下來”。這就是過早優(yōu)化是萬惡之源的原因;它浪費(fèi)了我們的時間,幾乎從來沒有真正有助于我們的性能改進(jìn)。
就 Big-O 而言,你可以認(rèn)為對你的程序而言,所有的語言都是 O(n),其中 n 是代碼或者指令的行數(shù)。對于同樣的指令,它們以同樣的速率增長。對于漸進(jìn)增長,一種語言的速度快慢并不重要,所有語言都是相同的。在這個邏輯下,你可以說,為你的應(yīng)用程序選擇一種語言僅僅是因?yàn)樗摹翱焖佟笔沁^早優(yōu)化的最終形式。你選擇某些預(yù)期快速的東西,卻沒有測量,也不理解瓶頸將在哪里。
- 為您的應(yīng)用選擇語言只是因?yàn)樗摹翱焖佟?,是過早優(yōu)化的最終形式。
優(yōu)化 Python
我最喜歡 Python 的一點(diǎn)是,它可以讓你一次優(yōu)化一點(diǎn)點(diǎn)代碼。假設(shè)你有一個 Python 的方法,你發(fā)現(xiàn)它是你的瓶頸。你對它優(yōu)化過幾次,可能遵循這里和那里的一些指導(dǎo),現(xiàn)在,你很肯定 Python 本身就是你的瓶頸。Python 有調(diào)用 C 代碼的能力,這意味著,你可以用 C 重寫這個方法來減少性能問題。你可以一次重寫一個這樣的方法。這個過程允許你用任何可以編譯為 C 兼容匯編程序的語言,編寫良好優(yōu)化后的瓶頸方法。這讓你能夠在大多數(shù)時間使用 Python 編寫,只在必要的時候都才用較低級的語言來寫代碼。
有一種叫做 Cython 的編程語言,它是 Python 的超集。它幾乎是 Python 和 C 的合并,是一種漸進(jìn)類型的語言。任何 Python 代碼都是有效的 Cython 代碼,Cython 代碼可以編譯成 C 代碼。使用 Cython,你可以編寫一個模塊或者一個方法,并逐漸進(jìn)步到越來越多的 C 類型和性能。你可以將 C 類型和 Python 的鴨子類型混在一起。使用 Cython,你可以獲得混合后的***組合,只在瓶頸處進(jìn)行優(yōu)化,同時在其他所有地方不失去 Python 的美麗。
星戰(zhàn)前夜的一幅截圖:這是用 Python 編寫的 space MMO 游戲。
當(dāng)您最終遇到 Python 的性能問題阻礙時,你不需要把你的整個代碼庫用另一種不同的語言來編寫。你只需要用 Cython 重寫幾個函數(shù),幾乎就能得到你所需要的性能。這就是星戰(zhàn)前夜采取的策略。這是一個大型多玩家的電腦游戲,在整個架構(gòu)中使用 Python 和 Cython。它們通過優(yōu)化 C/Cython 中的瓶頸來實(shí)現(xiàn)游戲級別的性能。如果這個策略對他們有用,那么它應(yīng)該對任何人都有幫助。或者,還有其他方法來優(yōu)化你的 Python。例如,PyPy 是一個 Python 的 JIT 實(shí)現(xiàn),它通過使用 PyPy 替掉 CPython(這是 Python 的默認(rèn)實(shí)現(xiàn)),為長時間運(yùn)行的應(yīng)用程序提供重要的運(yùn)行時改進(jìn)(如 web 服務(wù)器)。
讓我們回顧一下要點(diǎn):
- 優(yōu)化你最貴的資源。那就是你,而不是計算機(jī)。
- 選擇一種語言/框架/架構(gòu)來幫助你快速開發(fā)(比如 Python)。不要僅僅因?yàn)槟承┘夹g(shù)的快而選擇它們。
- 當(dāng)你遇到性能問題時,請找到瓶頸所在。
- 你的瓶頸很可能不是 CPU 或者 Python 本身。
- 如果 Python 成為你的瓶頸(你已經(jīng)優(yōu)化過你的算法),那么可以轉(zhuǎn)向熱門的 Cython 或者 C。
- 盡情享受可以快速做完事情的樂趣。
我希望你喜歡閱讀這篇文章,就像我喜歡寫這篇文章一樣。如果你想說謝謝,請為我點(diǎn)下贊。另外,如果某個時候你想和我討論 Python,你可以在 twitter 上艾特我(@nhumrich),或者你可以在 Python slack channel 找到我。
作者簡介:
Nick Humrich -- 堅(jiān)持采用持續(xù)交付的方法,并為之寫了很多工具。同是還是一名 Python 黑客與技術(shù)狂熱者,目前是一名 DevOps 工程師。
本文題目:告訴你為什么Python有點(diǎn)慢,但我卻無所謂?
本文地址:http://www.5511xx.com/article/cosjdgp.html


咨詢
建站咨詢
