中文字幕一区二区人妻电影,亚洲av无码一区二区乱子伦as ,亚洲精品无码永久在线观看,亚洲成aⅴ人片久青草影院按摩,亚洲黑人巨大videos

PyPy:速度更快的Python

發(fā)布于:2021-01-25 13:49:30

0

831

0

python PyPy Python解釋器 CPython

Python是開發(fā)人員中最受歡迎的編程語言之一,但是它有一定的局限性。例如,取決于應用程序,它的速度可能是某些低級語言的速度的100倍。這就是為什么一旦Python的速度成為用戶的瓶頸,許多公司就會用另一種語言重寫其應用程序的原因。但是,如果有一種方法可以保留Python的出色功能并提高其速度呢?那就是PyPy。

PyPy是一個非常兼容的Python解釋器,是CPython 2.7、3.6和即將推出的3.7的一個有價值的替代品。通過安裝和運行應用程序,可以顯著提高速度。您將看到多少改進取決于您正在運行的應用程序。

在本教程中,您將學習:

  • 如何使用PyPy安裝和運行代碼

  • PyPy在速度方面如何與CPython進行比較

  • PyPy的功能是什么以及它們如何使您的Python代碼運行得更快

  • PyPy的局限性是什么

本教程中的示例使用Python 3.6,因為那是PyPy兼容的最新Python版本。

Python和PyPy

Python語言規(guī)范用于許多實現中,例如CPython(用C編寫),Jython(用Java編寫),IronPython(為.NET編寫)和PyPy(用Python編寫)。

CPython是Python的原始實現,并且是迄今為止最受歡迎和最維護的。當人們提到Python時,他們通常不是指CPython。您現在可能正在使用CPython!

但是,由于CPython是高級解釋語言,因此CPython具有一定的局限性,不會為速度贏得任何榮譽。這就是PyPy可以派上用場的地方。由于它遵循Python語言規(guī)范,因此PyPy無需更改您的代碼庫,并且由于您將在下面看到的功能而可以顯著提高速度。

現在,您可能想知道為什么CPython如果使用相同的語法,就無法實現PyPy的出色功能。原因是實現這些功能將需要對源代碼進行巨大的更改,這將是一項艱巨的任務。

在不深入研究理論的情況下,讓我們看看PyPy的作用。

安裝

您的操作系統(tǒng)可能已經提供了PyPy軟件包。例如,在macOS上,您可以借助Homebrew進行安裝:

$ brew install pypy3

如果沒有,您可以下載適用于您的操作系統(tǒng)和體系結構的預構建二進制文件。完成下載后,只需解壓縮tarball或ZIP文件即可。然后,您可以執(zhí)行PyPy,而無需將其安裝在任何地方:

$ tar xf pypy3.6-v7.3.1-osx64.tar.bz2 $ ./pypy3.6-v7.3.1-osx64/bin/pypy3 Python 3.6.9 (?, Jul 19 2020, 21:37:06) [PyPy 7.3.1 with GCC 4.2.1] Type "help", "copyright", "credits" or "license" for more information.

在執(zhí)行上面的代碼之前,您需要位于下載二進制文件的文件夾中。有關完整說明,請參閱安裝文檔。

行動中的PyPy

現在,您已經安裝了PyPy,可以隨時使用它了!為此,創(chuàng)建一個名為的Python文件script.py,并將以下代碼放入其中:

total = 0  for i in range(1, 10000):      for j in range(1, 10000):          total += i + j           print(f"The result is {total}")

這是一個腳本,在兩個嵌套for循環(huán)中,將的數字1加到9,999,然后輸出結果。

要查看運行此腳本需要多長時間,請對其進行編輯以添加突出顯示的行:

{xunruicms_img_title}

該代碼現在執(zhí)行以下操作:

  • 第3行將當前時間保存到變量中start_time。

  • 第5至8行運行循環(huán)。

  • 第10行打印結果。

  • 第12行將當前時間保存到end_time。

  • 第13行顯示start_time和之間的差異,end_time以顯示運行腳本所需的時間。

嘗試使用Python運行它。這是我在2015 MacBook Pro上獲得的:

$ python3.6 script.py The result is 999800010000 It took 20.66 seconds to compute

現在使用PyPy運行它:

$ pypy3 script.py The result is 999800010000 It took 0.22 seconds to compute

在這個小的綜合基準中,PyPy的速度大約是Python的94倍!

有關更嚴格的基準測試,您可以查看PyPy Speed Center,開發(fā)人員在該中心每晚運行帶有不同可執(zhí)行文件的基準測試。

請記住,PyPy如何影響您的代碼性能取決于您的代碼在做什么。在某些情況下,PyPy實際上要慢一些,您將在后面看到。但是,就幾何平均而言,它的速度是Python的4.3倍。

PyPy及其功能

從歷史上看,PyPy提到了兩件事:

  1. 一個動態(tài)語言框架,用于為動態(tài)語言生成解釋器

  2. 一個Python實現使用框架

通過安裝PyPy并運行一個小腳本,您已經看到了第二個含義。您使用的Python實現是使用稱為RPython的動態(tài)語言框架編寫的,就像CPython是用C編寫而Jython是用Java編寫一樣。

但是您是否沒有早些時候告訴過PyPy是用Python編寫的?好吧,這有點簡化。PyPy之所以被稱為Python(而不是RPython)編寫的解釋器,是因為RPython使用與Python相同的語法。

為了清除所有內容,以下是PyPy的生產方式:

  1. 源代碼是用RPython編寫的。

  2. 所述RPython翻譯工具鏈被施加到代碼,這基本上使得代碼更高效。它還將代碼編譯為機器代碼,這就是Mac,Windows和Linux用戶必須下載不同版本的原因。

  3. 生成二進制可執(zhí)行文件。這是您用來運行小腳本的Python解釋器。

請記住,您無需完成所有這些步驟即可使用PyPy。該可執(zhí)行文件已經可供您安裝和使用。

而且,由于在框架和實現中使用相同的詞非常令人困惑,因此PyPy背后的團隊決定擺脫這種雙重用法。現在,PyPy僅指Python實現。該框架稱為RPython轉換工具鏈。

接下來,您將了解使PyPy在某些情況下比Python更好和更快的功能。

即時(JIT)編譯器

在了解什么是JIT編譯之前,讓我們退后一步,回顧一下諸如C之類的已編譯語言和諸如JavaScript之類的解釋語言的屬性。

編譯的編程語言性能更高,但是更難移植到不同的CPU體系結構和操作系統(tǒng)。解釋性編程語言更可移植,但是其性能比編譯語言差很多。這是頻譜的兩個極端。

然后是諸如Python之類的編程語言,它們同時進行編譯和解釋。具體來說,首先將Python編譯為中間字節(jié)碼,然后由CPython對其進行解釋。這使代碼的性能比用純解釋性編程語言編寫的代碼更好,并且保持了可移植性的優(yōu)勢。

但是,性能仍然遠不及編譯版本。原因是編譯后的代碼可以進行很多優(yōu)化,而這些優(yōu)化是字節(jié)碼無法實現的。

這就是即時(JIT)編譯器的用處。它試圖通過對機器代碼進行一些實際的編譯和一些解釋來獲得兩個方面的優(yōu)勢。簡而言之,以下是JIT編譯為提高性能而采取的步驟:

  1. 標識代碼中最常用的組件,例如循環(huán)中的函數。

  2. 在運行時將這些零件轉換為機器代碼。

  3. 優(yōu)化生成的機器代碼。

  4. 與優(yōu)化的機器代碼版本交換以前的實現。

還記得本教程開始時的兩個嵌套循環(huán)嗎?PyPy檢測到一次又一次地執(zhí)行相同的操作,將其編譯為機器代碼,優(yōu)化了機器代碼,然后交換了實現。這就是為什么您看到速度有了如此大的提高。

垃圾收集

每當您創(chuàng)建變量,函數或任何其他對象時,計算機就會為它們分配內存。最終,將不再需要其中一些對象。如果不清理它們,則計算機可能會耗盡內存并導致程序崩潰。

在C和C ++等編程語言中,通常必須手動處理此問題。其他編程語言(例如Python和Java)會自動為您完成此操作。這稱為自動垃圾收集,有幾種技術可以實現它。

CPython使用一種稱為引用計數的技術。本質上,每當引用對象時,Python對象的引用計數就增加,而在取消引用對象時,其計數就減少。當引用計數為零時,CPython會自動為該對象調用內存釋放函數。這是一種簡單有效的技術,但有一個陷阱。

當大對象樹的引用計數變?yōu)榱銜r,將釋放所有相關對象。結果,您可能有很長的暫停時間,在此期間您的程序根本無法執(zhí)行。

另外,在一個用例中,引用計數根本不起作用??紤]以下代碼:

class A(object):      pass  a = A()  a.some_property = a  del a

在上面的代碼中,您定義了新類。然后,創(chuàng)建該類的實例,并將其分配為自身的屬性。最后,刪除實例。

此時,該實例不再可訪問。但是,引用計數不會從實例中刪除實例,因為它具有對自身的引用,因此引用計數不為零。此問題稱為參考周期,無法使用參考計數解決。

這是CPython使用另一種稱為循環(huán)垃圾收集器的工具的地方。它從type對象的已知根開始遍歷內存中的所有對象。然后,它標識所有可到達的對象并釋放不可達的對象,因為它們不再存在。這解決了參考周期問題。但是,當內存中有大量對象時,它可能會導致更明顯的暫停。

另一方面,PyPy不使用引用計數。相反,它僅使用第二種技術,即循環(huán)查找器。也就是說,它定期從根開始遍歷活動對象。PyPy相對于CPython具有一些優(yōu)勢,因為它不會打擾引用計數,從而使內存管理上花費的總時間少于CPython。

另外,PyPy并沒有像CPython這樣的主要任務來完成所有工作,而是將工作分解為可變數量的片段,并逐個運行直到沒有剩余為止。這種方法在每個次要集合之后僅增加幾毫秒,而不是像CPython那樣一次性增加數百毫秒。

垃圾收集很復雜,并且有許多詳細信息超出了本教程的范圍。您可以在文檔中找到有關PyPy垃圾回收的更多信息。

PyPy的局限性

PyPy不是靈丹妙藥,并且不一定總是最適合您的任務的工具。它甚至可能使您的應用程序執(zhí)行速度比CPython慢得多。這就是為什么記住以下限制很重要。

C擴展不能很好地工作

PyPy最適合純Python應用程序。無論何時使用C擴展模塊,它的運行速度都比CPython中慢。原因是PyPy無法完全支持C擴展模塊,因此無法對其進行優(yōu)化。另外,PyPy必須模擬該部分代碼的引用計數,從而使其速度更慢。

在這種情況下,PyPy團隊建議刪除CPython擴展并將其替換為純Python版本,以便JIT可以看到它并進行優(yōu)化。如果這不是一個選擇,那么您將不得不使用CPython。

話雖如此,核心團隊正在致力于C擴展。一些軟件包已經被移植到PyPy并以同樣快的速度工作。

它僅適用于長期運行的程序

假設您想去一家離您家很近的商店。您可以步行或開車。

您的汽車顯然比腳快得多。但是,請考慮需要執(zhí)行以下操作:

  1. 去你的車庫。

  2. 啟動你的車。

  3. 稍微加熱汽車。

  4. 開車去商店。

  5. 查找停車位。

  6. 在返回途中重復該過程。

開車要涉及很多開銷,如果您想去的地方在附近,這并不總是值得的!

現在,想想如果您想去五十英里外的鄰近城市會發(fā)生什么。開車去那里而不是步行肯定是值得的。

盡管速度的差異并不像上面的類比那么明顯,但是PyPy和CPython也是一樣。

當您使用PyPy運行腳本時,它會做很多事情來使您的代碼運行更快。如果腳本太小,那么開銷將導致您的腳本運行速度比CPython中慢。另一方面,如果您的腳本運行時間很長,那么開銷會帶來可觀的性能紅利。

要親自查看,請在CPython和PyPy中運行以下小腳本:

{xunruicms_img_title}

使用PyPy運行時,開始時會有一個小的延遲,而CPython會立即運行它。確切地說,0.0004873276在使用CPython的2015 MacBook Pro上運行它需要幾秒鐘,而在0.0019447803PyPy上運行它需要幾秒鐘。

它不進行提前編譯

正如您在本教程開始時所看到的那樣,PyPy不是完全編譯的Python實現。它編譯Python代碼,但不是Python代碼的編譯器。由于Python固有的動態(tài)性,不可能將Python編譯成獨立的二進制文件并重新使用它。

PyPy是一個運行時解釋程序,它比完全解釋的語言要快,但是比完全編譯的語言(如C)要慢。

結論

PyPy是CPython的快速而強大的替代品。通過與腳本一起運行腳本,無需對代碼進行任何更改即可大大提高速度。但這不是靈丹妙藥。它有一些限制,您需要測試程序以查看PyPy是否可以提供幫助。

在本教程中,您學習了:

什么PyPy是

如何安裝PyPy并使用它運行腳本

PyPy在速度方面如何與CPython進行比較

PyPy具有什么功能以及如何提高程序速度

PyPy具有哪些限制,可能使其在某些情況下不適合

如果您的Python腳本需要提高速度,請嘗試PyPy。根據您的程序,您可能會得到一些明顯的速度改進!