欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

python 運行速度慢的原因

系統(tǒng) 3249 0

作者:Anthony Shaw 是 Python 軟件基金會成員和 Apache 基金會成員。

近來Python可謂人氣驟升。這門編程語言用于開發(fā)運維(DevOps)、數(shù)據(jù)科學、網(wǎng)站開發(fā)和安全。

然而,它沒有因速度而贏得任何獎牌。

Java在速度方面與C、C++、C#或Python相比如何?答案很大程度上取決于你運行的應用程序的類型。沒有哪個基準測試程序盡善盡美,不過The Computer Language Benchmarks Game(計算機語言基準測試游戲)是個不錯的起點。

十多年來,我一直提到計算機語言基準測試游戲;與Java、C#、Go、Java和C++等其他語言相比,Python是速度最慢的語言之一。除了Java等解釋語言外,這還包括JIT(C#和Java)以及AOT(C和C++)編譯器。

注意:我說“Python”時,其實指這種語言的參考實現(xiàn):CPython。我會在本文中提到其他運行時環(huán)境。

我想回答這個問題:Python運行完成類似的應用程序比另一種語言慢2倍至10倍時,為什么它這么慢,我們能不能讓它更快些?

下面是幾種常見的說法:

  • “它是GIL(全局解釋器鎖)”
  • “這是由于它是解釋的,而非編譯”
  • “這是由于它是一種動態(tài)類型語言”

那么,到底上述哪個原因?qū)π阅軒淼挠绊懽畲螅?

“它是GIL”

現(xiàn)代計算機搭載擁有多個內(nèi)核的CPU,有時搭載多個處理器。為了利用所有這些額外的處理能力,操作系統(tǒng)定義了一種名為線程的低級結(jié)構(gòu):一個進程(比如Chrome瀏覽器)可能生成多個線程,并擁有針對內(nèi)部系統(tǒng)的指令。這樣一來,如果某個進程特別耗費CPU資源,該負載可以在諸多核心之間分擔,這實際上讓大多數(shù)應用程序更快地完成任務。

我在寫這篇文章時,我的Chrome瀏覽器有44個線程開著。請記住這點:線程的結(jié)構(gòu)和API在基于POSIX的操作系統(tǒng)(比如Mac OS和Linux)與Windows OS之間是不同的。操作系統(tǒng)還處理線程的調(diào)度。

如果你之前沒有從事過多線程編程,需要盡快熟悉的一個概念就是鎖(lock)。與單線程進程不同,當你需要確保改變內(nèi)存中的變量時,多個線程并不同時試圖訪問/改變同樣的內(nèi)存地址。

CPython創(chuàng)建變量時,它會分配內(nèi)存,然后計算該變量的引用有多少,這個概念名為引用計數(shù)(reference counting)。如果引用數(shù)為0,那么它從系統(tǒng)釋放這部分內(nèi)存。這就是為什么在某個代碼段(比如for循環(huán)的范圍)內(nèi)創(chuàng)建一個“臨時”變量不會搞砸應用程序的內(nèi)存消耗。

當變量在多個線程內(nèi)共享時,就出現(xiàn)了這個難題:CPython如何鎖定引用計數(shù)。有一個“全局解釋器鎖”,它小心地控制線程執(zhí)行。解釋器一次只能執(zhí)行一個操作,無論它有多少線程。

這對Python應用程序的性能來說意味著什么?

如果你有單線程、單個解釋器的應用程序,這對速度不會有影響。刪除GIL根本不會影響你代碼的性能。

如果你想通過使用線程機制在單個解釋器(Python進程)內(nèi)實現(xiàn)并發(fā)功能,而且線程是IO密集型(比如網(wǎng)絡IO或磁盤IO),你會看到GIL爭奪的后果。

上圖來自大衛(wèi)?比茲利(David Beazley)撰寫的《GIL可視化》文章:http://dabeaz.blogspot.com/2010/01/python-gil-visualized.html

如果你有Web應用程序(比如Django),又在使用WSGI,那么針對Web應用程序的每個請求都是一個單獨的Python解釋器,所以每個請求只有一個鎖。由于Python解釋器啟動緩慢,一些WSGI實現(xiàn)擁有“守護進程模式”,這可以讓一個或多個Python進程為你保持活躍狀態(tài)。

其他Python運行時環(huán)境怎么樣?

PyPy有一個GIL,它通常比CPython快3倍。

Jython之所以沒有GIL,是由于Jython中的Python線程由Java線程表示,受益于JVM內(nèi)存管理系統(tǒng)。

Java如何執(zhí)行此任務?

好吧,首先所有Java引擎都使用標記-清除(mark-and-sweep)垃圾收集機制。如上所述,GIL的主要需求是CPython的內(nèi)存管理算法。

Java沒有GIL,但它也是單線程的,所以它不需要內(nèi)存管理算法。Java的事件循環(huán)和承諾回調(diào)(Promise/Callback)模式是實現(xiàn)異步編程以代替并發(fā)的方法。Python與asyncio事件循環(huán)有相似之處。

“這是由于它一種解釋語言”

我常聽到這個觀點,但覺得這過于簡化了CPython的實際工作方式。如果你在終端上編寫了python my.py,那么CPython會啟動讀取、分析、解析、編譯、解釋和執(zhí)行代碼的一長串操作。

如果你對這個過程的機理頗感興趣,我之前寫過一篇文章:《6分鐘內(nèi)修改Python語言》(https://hackernoon.com/modifying-the-python-language-in-7-minutes-b94b0a99ce14)。

這個過程的一個重要節(jié)點是創(chuàng)建.pyc文件;在編譯階段,字節(jié)碼序列寫入到Python 3中__pycache__/里面的一個文件或Python 2中的同一個目錄。這不僅適用于你的腳本,還適用于導入的所有代碼,包括第三方模塊。

所以在大部分時間(除非你編寫的是只運行一次的代碼?),Python解釋字節(jié)碼,并在本地執(zhí)行。相比之下Java和C#.NET:

Java編譯成一種“中間語言”,Java虛擬機讀取字節(jié)碼,并即時編譯成機器碼。.NET CIL也一樣,.NET公共語言運行時環(huán)境(CLR)使用即時編譯,將編譯后代碼編譯成機器碼。

那么,既然都使用虛擬機和某種字節(jié)碼,為什么Python在基準測試中比Java和C#都要慢得多呢?首先,.NET和Java是JIT編譯型的。

JIT或即時編譯需要一種中間語言,以便將代碼拆分成塊(或幀)。提前(AOT)編譯器旨在確保CPU在任何交互發(fā)生之前能理解每一行代碼。

JIT本身不會使執(zhí)行變得更快,因為它仍然執(zhí)行相同的字節(jié)碼序列。然而,JIT讓代碼在運行時能夠加以優(yōu)化。一個好的JIT優(yōu)化器會看到應用程序的哪些部分在頻繁執(zhí)行,這些代碼稱之為“熱點代碼”(hot spot)。然后,它會對這些代碼進行優(yōu)化,其辦法是把它們換成更高效的版本。

這就意味著當你的應用程序一次又一次地執(zhí)行相同的操作時,運行速度可以顯著加快。另外記住一點:Java和C#是強類型語言,因此優(yōu)化器可以對代碼做出多得多的假設。

PyPy有JIT,如上所述,其速度比CPython快得多。這篇性能基準測試文章作了更詳細的介紹:《哪個Python版本的速度最快?》(https://hackernoon.com/which-is-the-fastest-version-of-python-2ae7c61a6b2b)。

那么,CPython為什么不使用JIT呢?

JIT存在幾個缺點:缺點之一是啟動時間。CPython的啟動時間已經(jīng)比較慢了,PyPy的啟動時間比CPython還要慢2倍至3倍。眾所周知,Java虛擬機的啟動速度很慢。.NET CLR通過系統(tǒng)開啟時啟動解決了這個問題,但CLR的開發(fā)人員還開發(fā)了操作系統(tǒng),CLR在它上面運行。

如果你有一個Python進程長時間運行,代碼因含有“熱點代碼”而可以優(yōu)化,那么JIT大有意義。

然而,CPython是一種通用實現(xiàn)。所以,如果你在使用Python開發(fā)命令行應用程序,每次調(diào)用CLI都得等待JIT啟動會慢得要命。

CPython不得不試圖滿足盡可能多的用例(use case)。之前有人試過將JIT插入到CPython中,但這個項目基本上擱淺了。

如果你想獲得JIT的好處,又有適合它的工作負載,不妨使用PyPy。

“這是由于它是一種動態(tài)類型語言”

在“靜態(tài)類型”語言中,你在聲明變量時必須指定變量的類型。這樣的語言包括C、C++、Java、C#和Go。

在動態(tài)類型語言中,仍然存在類型這個概念,但變量的類型是動態(tài)的。

在這個示例中,Python創(chuàng)建了一個有相同名稱、str類型的第二個變量,并釋放為a的第一個實例創(chuàng)建的內(nèi)存。

靜態(tài)類型語言不是為了給你添堵而設計的,它們是兼顧CPU的運行方式設計的。如果一切最終需要等同于簡單的二進制操作,你就得將對象和類型轉(zhuǎn)換成低級數(shù)據(jù)結(jié)構(gòu)。

Python為你這么做這項工作,你永遠看不到,也不需要操心。

不必聲明類型不是導致Python速度慢的原因,Python語言的設計使你能夠讓幾乎一切都是動態(tài)的。你可以通過猴子補丁(monkey-patch),加入對運行時聲明的值進行低級系統(tǒng)調(diào)用的代碼。幾乎一切都有可能。

正是這種設計使得優(yōu)化Python異常困難。

為了說明我的觀點,我將使用可在Mac OS中使用的一種名為Dtrace的系統(tǒng)調(diào)用跟蹤工具。CPython發(fā)行版并未內(nèi)置DTrace,所以你得重新編譯CPython。我使用3.6.6進行演示。

python 運行速度慢的原因_第1張圖片

現(xiàn)在python.exe將在整個代碼中使用Dtrace跟蹤器。保羅?羅斯(Paul Ross)寫了一篇關于Dtrace的雜談(https://github.com/paulross/dtrace-py#the-lightning-talk)。你可以下載Python的DTrace啟動文件(https://github.com/paulross/dtrace-py/tree/master/toolkit)來測量函數(shù)調(diào)用、執(zhí)行時間、CPU時間、系統(tǒng)調(diào)用和各種好玩的指標。比如

py_callflow跟蹤器顯示你應用程序中的所有函數(shù)調(diào)用。

python 運行速度慢的原因_第2張圖片

那么,Python的動態(tài)類型會讓它變慢嗎?

  • 比較和轉(zhuǎn)換類型的開銷很大,每次讀取、寫入或引用一個變量,都要檢查類型。
  • 很難優(yōu)化一種極具動態(tài)性的語言。Python的許多替代語言之所以快得多,原因在于它們?yōu)榱诵阅茉陟`活性方面作出了犧牲。
  • Cython 結(jié)合了C-Static類型和Python來優(yōu)化類型已知的代碼,可以將性能提升84倍。

結(jié)論

Python之所以速度慢,主要是由于動態(tài)性和多功能性。它可用作解決各種問題的工具,Python有更優(yōu)化、速度更快的幾個替代方案。

然而,有一些方法可以優(yōu)化你的Python應用程序,比如通過充分利用異步、深入了解分析工具以及考慮使用多個解釋器。

對于啟動時間不重要、代碼會受益于JIT的應用程序來說,不妨考慮PyPy。

對于性能至關重要,又有更多靜態(tài)類型變量的部分代碼而言,不妨考慮使用Cython。

本文轉(zhuǎn)載自:https://465914.kuaizhan.com/36/57/p543294672f5b80


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产一区在线免费观看 | 日本一区二区三区不卡在线看 | 午夜影视在线观看 | 99视频有精品视频免费观看 | 欧美高清另类自拍视频在线看 | 国产精品久久久久不卡 | 深夜影院破解版免费vip | 欧美日韩一区二区在线 | 久久久久久影院 | 麻豆精品传媒一二三区在线视频 | 国产精品久久久久久搜索 | 欧美精品一区二 | 操人视频 | 香蕉国产人午夜视频在线 | 99久久人妻无码精品系列性欧美 | 天天干天天舔天天操 | 日本毛片高清免费视频 | 看亚洲a级一级毛片 | 欧美一级二级视频 | 天干天夜啪天天碰 | 97日日摸天天碰免费视频 | 欧美精品在线一区二区三区 | 亚洲国产精品99久久久久久久久 | 性夜黄a爽影免费看 | 福利视频网页 | 午夜亚洲国产成人不卡在线 | 干天天 | 午夜亚洲 | 欧美成人一级片 | 日韩三级中文字幕 | 国产一区二区三区在线免费观看 | 色综合久久天天综合网 | 亚洲色图套图 | 中文字幕在线第一页 | 国产成人久久婷婷精品流白浆 | 国产2区| 污视频在线网站 | 国产日产亚洲欧美综合另类 | 色婷婷色综合缴情在线 | 蜜桃免费一区二区三区 | 精品视频在线免费看 |