<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用 PyPy 讓你的 Python 代碼運(yùn)行得更快!

          共 5754字,需瀏覽 12分鐘

           ·

          2020-11-17 04:12

          Python是開發(fā)人員中最常用的編程語(yǔ)言之一,但它有一定的局限性。例如,對(duì)于某些應(yīng)用程序而言,它的運(yùn)行速度可能比其它語(yǔ)言低100倍。這就是為什么當(dāng)Python的運(yùn)行速度成為用戶瓶頸后,許多公司會(huì)用另一種語(yǔ)言重寫他們的應(yīng)用程序。但是有沒有一種方法既可以保持Python的特性又能提高速度呢?它就是PyPy
          PyPy是一種非常兼容的Python解釋器,它是CPython2.7、3.6和即將推出的3.7的一種值得替代的方法。在安裝和運(yùn)行應(yīng)用程序時(shí)使用它,可以顯著提高速度。速度提高多少取決于你運(yùn)行的應(yīng)用程序。
          在本教程中,您將學(xué)習(xí):
          • 如何使用PyPy安裝和運(yùn)行代碼
          • PyPy與CPython在速度方面的比較
          • PyPy的功能及其如何使Python代碼更快地運(yùn)行
          • 本教程中的示例使用 Python 3.6 ,因?yàn)樗荘yPy兼容的最新 Python 版本。
          PyPy 簡(jiǎn)介
          Python解釋器可以用多種語(yǔ)言來(lái)實(shí)現(xiàn),如CPython(用C編寫)、Jython(用Java編寫)、Iron Python(用.NET編寫)和PyPy(用Python編寫)。
          CPython是Python解釋器的最初實(shí)現(xiàn),也是迄今為止使用最廣和最多維護(hù)的。當(dāng)我們從Python官方網(wǎng)站下載并安裝好Python 3.x后,我們就直接獲得了一個(gè)官方版本的解釋器:CPython。這個(gè)解釋器是用C語(yǔ)言開發(fā)的,所以叫CPython。在命令行下運(yùn)行python就是啟動(dòng)CPython解釋器。
          但是,由于CPython是一種高級(jí)的解釋語(yǔ)言,因此它有一定的局限性,并且在速度方面沒有任何優(yōu)勢(shì)。這就是PyPy可以起作用的地方。由于它符合Python語(yǔ)言規(guī)范,因此Py Py不需要對(duì)代碼庫(kù)進(jìn)行任何更改,并且可以通過下面的功能顯著提高速度。
          現(xiàn)在,您可能想知道,如果CPython使用相同的語(yǔ)法,為什么它不實(shí)現(xiàn)Py Py的強(qiáng)大功能。原因是,實(shí)施這些功能需要對(duì)源代碼進(jìn)行巨大的更改,這將是一項(xiàng)非常繁瑣的工作。
          我們來(lái)粗略看一下如何在實(shí)際操作中使用PyPy。
          安裝
          您的操作系統(tǒng)可能已提供PyPy軟件包。例如,在Mac OS上,您可以在Homebrew的幫助下安裝它:
          $?brew?install?pypy3
          或者您也可以下載與操作系統(tǒng)匹配的二進(jìn)制文件。完成下載后,只需打開tarball或ZIP文件即可。然后,您可以執(zhí)行以下操作:
          $?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í)行該命令。有關(guān)完整的說明,請(qǐng)參閱安裝文檔。
          運(yùn)行 PyPy
          您現(xiàn)在已經(jīng)安裝了Py Py,并且即將運(yùn)行它!為此,請(qǐng)創(chuàng)建一個(gè)名為script.py的Python文件,并將以下代碼放入其中:
          total?=?0
          for?i?in?range(1,?10000):
          ????for?j?in?range(1,?10000):
          ????????total?+=?i?+?j

          print(f"The?result?is?{total}")
          在兩個(gè)嵌套的for循環(huán)中,將1到9,999之間的數(shù)字相加,并打印結(jié)果。
          查看運(yùn)行此腳本需要多長(zhǎng)時(shí)間:
          import?time

          start_time?=?time.time()

          total?=?0
          for?i?in?range(1,?10000):
          ????for?j?in?range(1,?10000):
          ????????total?+=?i?+?j

          print(f"The?result?is?{total}")

          end_time?=?time.time()
          print(f"It?took?{end_time-start_time:.2f}?seconds?to?compute")
          該代碼現(xiàn)在執(zhí)行以下操作:
          • 第3行將當(dāng)前時(shí)間保存到變量start_time
          • 第5至8行運(yùn)行循環(huán)。
          • 第10行打印結(jié)果。
          • 第12行將當(dāng)前時(shí)間保存為end_time
          • 第13行打印開始時(shí)間和結(jié)束時(shí)間之間的差值,以顯示運(yùn)行腳本所需的時(shí)間。
          用Python來(lái)運(yùn)行它。下面是我在Mac Book Pro上的結(jié)果:
          $?python3.6?script.py
          The?result?is?999800010000
          It?took?20.66?seconds?to?compute
          現(xiàn)在使用Py Py運(yùn)行它:
          $?pypy3?script.py
          The?result?is?999800010000
          It?took?0.22?seconds?to?compute
          在這個(gè)小實(shí)驗(yàn)中,PyPy的速度大約是Python的94倍!
          您可以通過瀏覽 PyPy Speed Center 來(lái)查看更多嚴(yán)格的測(cè)試。
          請(qǐng)記住,PyPy如何影響代碼的性能取決于您用代碼來(lái)做什么。在某些情況下,Py Py實(shí)際上較慢,稍后會(huì)看到。但是,就幾何平均而言,它的速度是Python的4.3倍。
          PyPy及其特性
          Py Py有兩種定義:
          1、用于生成動(dòng)態(tài)語(yǔ)言解釋器的動(dòng)態(tài)語(yǔ)言框架 2、使用該框架的Python實(shí)現(xiàn)
          您應(yīng)該已經(jīng)意識(shí)到了第二個(gè)問題。您使用的Python實(shí)現(xiàn)是使用稱為RPython的動(dòng)態(tài)語(yǔ)言框架編寫的,就像CPython是用C編寫的,而Jython是用Java編寫的一樣。
          但之前文中不是提到PyPy是用Python編寫的嗎?嗯,這有點(diǎn)簡(jiǎn)單。PyPy成為用Python編寫的Python解釋器(而不是RPython)這么說的原因是RPython使用了與Python相同的語(yǔ)法。
          PyPy是怎么來(lái)的?需要解釋以下幾點(diǎn):
          1、它的源代碼是用RPython編寫。
          2、RPython轉(zhuǎn)換工具應(yīng)用到了代碼中,從根本上提高了代碼效率,還可以將代碼編譯為機(jī)器代碼,這就是Mac,Windows和Linux用戶必須下載不同版本的原因。
          3、用上述方式生成的二進(jìn)制可執(zhí)行文件,就是你運(yùn)行的Python解釋器。
          你不需要執(zhí)行上述所有這些步驟來(lái)使用PyPy。因?yàn)橐呀?jīng)有提供您安裝和使用的可執(zhí)行文件。
          此外,由于在框架和實(shí)現(xiàn)中使用同一個(gè)詞非常令人困惑,PyPy背后的團(tuán)隊(duì)決定放棄這種雙重用法。現(xiàn)在,PyPy僅指Python解釋器,而框架被稱為RPython轉(zhuǎn)換工具。
          接下來(lái),您將了解在什么情況下使用PyPy比Python更好、更快。
          Just-In-Time (JIT) 編譯器
          在了解JIT編譯器的內(nèi)容之前,讓我們先回顧一下已編譯語(yǔ)言(如C)和解釋語(yǔ)言(如JavaScript)的特性。
          在編譯型語(yǔ)言寫的程序執(zhí)行之前,需要一個(gè)專門的編譯過程,把源代碼編譯成機(jī)器語(yǔ)言的文件,如exe格式的文件,以后要再運(yùn)行時(shí),直接使用編譯結(jié)果即可,如直接運(yùn)行exe文件。因?yàn)橹恍杈幾g一次,以后運(yùn)行時(shí)不需要編譯,所以編譯型語(yǔ)言執(zhí)行效率高。與特定平臺(tái)相關(guān),一般無(wú)法移植到其他平臺(tái)。如C、C++、Objective等都屬于編譯型語(yǔ)言。
          解釋型語(yǔ)言不需要事先編譯,其直接將源代碼解釋成機(jī)器碼并立即執(zhí)行,所以只要某一平臺(tái)提供了相應(yīng)的解釋器即可運(yùn)行該程序。解釋型語(yǔ)言每次運(yùn)行都需要將源代碼解釋稱機(jī)器碼并執(zhí)行,效率較低;只要平臺(tái)提供相應(yīng)的解釋器,就可以運(yùn)行源代碼,所以可以方便源程序移植。
          然后還有一些編程語(yǔ)言,例如Python,它混合了編譯和解釋。具體來(lái)說,Python首先編譯為字節(jié)碼,然后由CPython解釋。這使代碼的性能優(yōu)于用純解釋型語(yǔ)言編寫的代碼,并保持可移植性優(yōu)勢(shì)。
          但是它的性能仍然遠(yuǎn)遠(yuǎn)低于編譯型語(yǔ)言。其原因是,編譯后的代碼可以執(zhí)行許多優(yōu)化,而字節(jié)碼是不可能的。
          這就是JIT編譯器的來(lái)源。它試圖通過對(duì)機(jī)器代碼進(jìn)行一些編譯和一些解釋來(lái)同時(shí)獲得兩種優(yōu)勢(shì)。簡(jiǎn)而言之,以下是JIT編譯為提供更快性能所采取的步驟:
          1、識(shí)別代碼中最常用的組件,如循環(huán)中的函數(shù)。
          2、運(yùn)行時(shí)將這些部件轉(zhuǎn)換為機(jī)器代碼。
          3、優(yōu)化生成的機(jī)器代碼。
          4、用優(yōu)化的機(jī)器代碼版本取代之前的實(shí)現(xiàn)。
          還記得教程開頭的兩個(gè)嵌套循環(huán)嗎?PyPy檢測(cè)到重復(fù)執(zhí)行相同操作時(shí),將其編譯為機(jī)器代碼,優(yōu)化機(jī)器代碼,然后轉(zhuǎn)換實(shí)現(xiàn)。這也是為什么您會(huì)看到這樣的結(jié)果。
          垃圾回收機(jī)制
          無(wú)論何時(shí)創(chuàng)建變量、函數(shù)或任何其他對(duì)象,您的計(jì)算機(jī)都會(huì)給它們分配內(nèi)存。最終,其中一些對(duì)象將不再需要。如果不及時(shí)清理,計(jì)算機(jī)可能會(huì)耗盡內(nèi)存并使程序崩潰。
          在C和C++等編程語(yǔ)言中,通常必須手動(dòng)處理此問題。其他編程語(yǔ)言(如Python和Java)會(huì)自動(dòng)為您執(zhí)行此操作。這被稱為自動(dòng)垃圾回收機(jī)制。
          CPython使用一種稱為引用計(jì)數(shù)的技術(shù)。實(shí)質(zhì)上,每當(dāng)引用對(duì)象時(shí),Python對(duì)象的引用計(jì)數(shù)都會(huì)增加,而在取消引用該對(duì)象時(shí)則遞減計(jì)數(shù)。當(dāng)引用計(jì)數(shù)為零時(shí),CPython會(huì)自動(dòng)為該對(duì)象調(diào)用內(nèi)存釋放函數(shù)。這是一種簡(jiǎn)單有效的技術(shù),但有一個(gè)陷阱。
          當(dāng)大型對(duì)象樹的引用計(jì)數(shù)變?yōu)榱銜r(shí),所有相關(guān)對(duì)象將被釋放。因此,您可能有很長(zhǎng)的暫停時(shí)間,在此期間您的程序根本無(wú)法執(zhí)行。
          此外,還有一個(gè)例子,其中引用計(jì)數(shù)根本不起作用。如下所示:
          class?A(object):
          ????pass

          a?=?A()
          a.some_property?=?a
          del?a
          在上面的代碼中,定義了新的類,然后,創(chuàng)建一個(gè)實(shí)例,并將其指定為其自身的屬性。最后,刪除實(shí)例。
          此時(shí),實(shí)例將不再可訪問。但是,引用計(jì)數(shù)不會(huì)從內(nèi)存中刪除實(shí)例,因?yàn)樗哂袑?duì)自身的引用,因此引用計(jì)數(shù)不是零。此問題被稱為引用循環(huán),無(wú)法使用引用計(jì)數(shù)解決。
          這是CPython使用的另一個(gè)工具,稱為循環(huán)垃圾回收器。它從已知根(如類型對(duì)象)開始遍歷內(nèi)存中的所有對(duì)象。然后,它標(biāo)識(shí)所有可訪問的對(duì)象,并釋放不可訪問的對(duì)象,因?yàn)樗鼈儾辉俅嬖凇_@樣就解決了引用循環(huán)問題。但是,當(dāng)內(nèi)存中存在大量對(duì)象時(shí),它可能會(huì)創(chuàng)建更明顯的暫停。
          另一方面,PyPy不使用引用計(jì)數(shù)。相反,它只使用第二種技術(shù),即循環(huán)查找器。也就是說,它會(huì)定期從根開始遍歷活動(dòng)對(duì)象。這使PyPy比CPython具有一些優(yōu)勢(shì),因?yàn)樗恍枰紤]引用計(jì)數(shù),從而使內(nèi)存管理花費(fèi)的總時(shí)間少于CPython。
          此外,PyPy將工作拆分為可變數(shù)量的部分,并運(yùn)行每個(gè)部分,直到?jīng)]有剩余部分為止。此方法只在每個(gè)次要集合之后添加幾毫秒,而不像CPython那樣一次添加數(shù)百毫秒。
          垃圾回收機(jī)制非常復(fù)雜,并且有許多超出本教程范圍的內(nèi)容。您可以在文檔中找到有關(guān)PyPy垃圾回收機(jī)制的詳細(xì)信息。
          PyPy的局限性
          PyPy并非萬(wàn)能,它不是一個(gè)適合您所有任務(wù)的工具。它甚至可能使應(yīng)用程序的執(zhí)行速度比CPython慢得多。這就是為什么您必須記住以下局限性。
          它不適用于C擴(kuò)展
          PyPy最適合純Python應(yīng)用程序。無(wú)論何時(shí)使用C擴(kuò)展模塊,它的運(yùn)行速度都要比在CPython中慢得多。原因是PyPy無(wú)法優(yōu)化C擴(kuò)展模塊,因?yàn)樗鼈儾皇芡耆С帧4送猓琍yPy必須模擬代碼中的引用計(jì)數(shù),使其更慢。
          在這種情況下,PyPy團(tuán)隊(duì)建議去掉CPython擴(kuò)展并將其替換為純Python版本。如果不行的話,則必須使用CPython。
          盡管如此,核心團(tuán)隊(duì)正在處理C擴(kuò)展。有些軟件包已被移植到PyPy,并且工作速度也同樣快。
          它只適用于長(zhǎng)時(shí)間運(yùn)行的程序
          想象一下你想去一家離你家很近的商店。您既可以直接走路前往,也可以開車。
          您的車明顯比您的腳快得多。但是,請(qǐng)考慮需要您完成的步驟:
          1.去你的車庫(kù)。?
          2、開車。?
          3、給車預(yù)熱。?
          4、開車去商店。
          5、尋找停車位。?
          6、在返回途中重復(fù)此過程。
          開車需要一系列麻煩的步驟,如果你想去的地方就在附近,那就不一定值得了。
          現(xiàn)在想想,如果你想去50公里外的鄰近城市,會(huì)發(fā)生什么?開車去那里肯定是值得的,而不是步行去。
          雖然速度上的對(duì)比并不像上面的類比那樣明顯,但PyPy和CPython和這個(gè)道理一樣。
          當(dāng)使用PyPy運(yùn)行腳本時(shí),它會(huì)執(zhí)行許多操作以使代碼運(yùn)行得更快。如果腳本本身很簡(jiǎn)單,則實(shí)際腳本運(yùn)行速度會(huì)低于CPython。另一方面,如果您有一個(gè)長(zhǎng)時(shí)間運(yùn)行的腳本,那么可能會(huì)帶來(lái)顯著的性能提升。
          想親自感受一下的話,請(qǐng)?jiān)贑Python和PyPy中運(yùn)行以下小腳本:
          import?time

          start_time?=?time.time()

          for?i?in?range(100):
          ????print(i)

          end_time?=?time.time()
          print(f"It?took?{end_time-start_time:.10f}?seconds?to?compute")
          當(dāng)您使用PyPy運(yùn)行它時(shí),開始時(shí)會(huì)有一個(gè)小延遲,而CPython會(huì)立即運(yùn)行它。在Mac Book Pro上運(yùn)行它,用CPython需要0.0004873276秒,用PyPy需要0.0019447803秒。
          它不執(zhí)行提前編譯
          正如您在本教程開頭所看到的,PyPy不是一個(gè)完全編譯型的Python實(shí)現(xiàn)。它編譯Python代碼,但不是Python代碼的編譯器。由于Python固有的一些特性,導(dǎo)致無(wú)法將Python編譯為獨(dú)立的二進(jìn)制文件并重用它。
          Py Py比完全解釋型的語(yǔ)言快,但比完全編譯的語(yǔ)言(如C)慢。
          總結(jié)
          PyPy是CPython的一種快速且功能強(qiáng)大的替代方案。使用它運(yùn)行腳本,您可以在不更改代碼的情況下大大提高速度。但它也不是萬(wàn)能的,有一些局限性。
          在本教程中,您學(xué)習(xí)了:
          • PyPy是什么?
          • 如何安裝PyPy并使用它運(yùn)行腳本
          • PyPy與CPython在速度方面的比較
          • PyPy的功能及其如何提高程序速
          • 在哪些情況下PyPy會(huì)有局限性
          如果您的Python腳本需要稍微提高速度,歡迎嘗試PyPy!


          長(zhǎng)按掃碼添加“Python小助手”?

          一起討論P(yáng)yPy!

          ▼點(diǎn)擊成為社區(qū)會(huì)員? ?喜歡就點(diǎn)個(gè)在看吧

          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  性无码一区二区三区 | 免费在线操逼视频 | 麻豆精品秘 国产传媒潘甜甜 | 91性爱在线观看 | 首页亚洲中文字幕视频 |