<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>

          Python高效代碼實(shí)踐:性能、內(nèi)存和可用性

          共 6465字,需瀏覽 13分鐘

           ·

          2021-03-11 06:22

          點(diǎn)擊上方Python知識(shí)圈,設(shè)為星標(biāo)

          回復(fù)100獲取100題PDF

          閱讀文本大概需要 5 分鐘

          譯者:Prodesire  |  來(lái)自《編程小記》
          原文:https://dwz.cn/r4N2hvht
          譯文:https://zhuanlan.zhihu.com/p/28675694


          遵循最佳做法的代碼庫(kù)在當(dāng)今世界能得到高度評(píng)價(jià)。如果您的項(xiàng)目是開(kāi)源的,這會(huì)是一個(gè)吸引優(yōu)秀開(kāi)發(fā)人員的方式。作為開(kāi)發(fā)人員,您想要編寫(xiě)高效且優(yōu)化的代碼:
          占用盡可能小的內(nèi)存、執(zhí)行地更快、看起來(lái)整潔、文檔正確、遵循標(biāo)準(zhǔn)風(fēng)格指南,并且易于被新開(kāi)發(fā)者理解。
          這里討論的實(shí)踐可能有助于您為開(kāi)源組織做出貢獻(xiàn),向在線評(píng)審(Online Judge)提交解決方案,使用機(jī)器學(xué)習(xí)處理大量數(shù)據(jù)處理問(wèn)題,或開(kāi)發(fā)自己的項(xiàng)目。

          1. 盡量不要對(duì)內(nèi)存置之不理

          一個(gè)簡(jiǎn)單的 Python 程序在內(nèi)存上可能不會(huì)引起很多問(wèn)題,但在高內(nèi)存消耗的項(xiàng)目中內(nèi)存使用變得至關(guān)重要。從一開(kāi)始開(kāi)發(fā)大項(xiàng)目時(shí),合理使用內(nèi)存是明智的。
          與 C/C ++ 不同,Python 解釋器會(huì)進(jìn)行內(nèi)存管理,用戶無(wú)法自己控制。Python 中的內(nèi)存管理涉及包含所有Python對(duì)象和數(shù)據(jù)結(jié)構(gòu)的專(zhuān)用堆。
          Python 內(nèi)存管理器內(nèi)部確保對(duì)這個(gè)專(zhuān)用堆的管理。當(dāng)您創(chuàng)建對(duì)象時(shí),Python 虛擬機(jī)處理所需的內(nèi)存,并決定將其放置在內(nèi)存布局中的特定位置。
          然而,如何更好地了解事情的工作原理和不同的方法來(lái)做事情,可以幫助您最大限度地減少程序的內(nèi)存使用量。
          使用生成器來(lái)計(jì)算大量的結(jié)果
          生成器可進(jìn)行惰性計(jì)算。您可以通過(guò)遍歷來(lái)使用它們:顯示地使用 “for” 或者隱式地將其傳遞給任何方法或構(gòu)造。
          生成器可以返回多個(gè)項(xiàng),就像返回一個(gè)列表 —— 不是一次返回所有,而是一個(gè)接一個(gè)地返回。生成器會(huì)暫停,直到下一個(gè)項(xiàng)被請(qǐng)求。在 這里[1] 閱讀更多關(guān)于 Python 生成器的內(nèi)容。
          對(duì)于大量數(shù)字/數(shù)據(jù)的處理,您可以使用像 Numpy 這樣的庫(kù),它可以優(yōu)雅地處理內(nèi)存管理。
          • 使用 format 而不是 “+” 來(lái)生成字符串 —— 在Python中,str 是不可變的,所以每對(duì)連接都必須將左、右字符串復(fù)制到新的字符串中。如果連接長(zhǎng)度為10的四個(gè)字符串,則將復(fù)制(10+10) + ((10+10)+10) + (((10+10)+10)+10) = 90 個(gè)字符,而不是 40 字符。隨著字符串?dāng)?shù)量和大小的增加,事情會(huì)變得越來(lái)越糟。Java 有時(shí)將一系列的連接轉(zhuǎn)換為使用StringBuilder 來(lái)優(yōu)化這種情況,但是 CPython 沒(méi)有。因此,建議使用 .format 或 % 語(yǔ)法。如果您不能在 .format 和 % 之間選擇,請(qǐng)查看 這個(gè)有趣的 StackOverflow 問(wèn)題[2] 。

          • 定義 Python 類(lèi)時(shí)使用槽(slots)。您可以通過(guò)將類(lèi)中的 __slots__ 設(shè)置為固定的屬性名稱(chēng)列表,來(lái)告訴 Python 不要使用動(dòng)態(tài)字典,只為一組固定的屬性分配空間,從而消除了為每個(gè)對(duì)象使用一個(gè)字典的開(kāi)銷(xiāo)。在 這里[3] 閱讀更多關(guān)于槽的內(nèi)容。

          • 您可以通過(guò)使用內(nèi)置的模塊(如 resource 和 objgraph)來(lái)跟蹤對(duì)象級(jí)別的內(nèi)存使用情況。

          • 在 Python 中管理內(nèi)存泄漏可能是一項(xiàng)艱巨的任務(wù),但幸運(yùn)的是有一些工具(如 heapy)用于調(diào)試內(nèi)存泄漏。Heapy 可以與 objgraph 一起使用來(lái)觀察 diff 對(duì)象的分配隨時(shí)間而增長(zhǎng)。Heapy 可以顯示哪些對(duì)象占用最多的內(nèi)存。Objgraph 可以幫助您找到反向引用,以明白為什么它們不能被釋放。您可以在 這里[4] 閱讀更多關(guān)于在Python中診斷內(nèi)存泄漏的信息。

          您可以在 這里[5] 閱讀由 Theano 的開(kāi)發(fā)人員編寫(xiě)的關(guān)于 Python 內(nèi)存管理的細(xì)節(jié)。

          2. Python2 還是 Python3

          當(dāng)開(kāi)始一個(gè)新的 Python 項(xiàng)目,或是只學(xué)習(xí) Python,您可能會(huì)發(fā)現(xiàn)自己在選擇 Python2 還是Python3 上十分糾結(jié)。這是一個(gè)廣泛討論的話題,在網(wǎng)上有許多觀點(diǎn)和好的解釋。
          一方面,Python3 有一些很棒的新特性。另一方面,您可能希望使用僅支持 Python2 的包,而Python3 不能向后兼容。這意味著在 Python3.x 的解釋器上運(yùn)行 Python2 的代碼可能會(huì)拋出錯(cuò)誤。
          不過(guò),編寫(xiě)能同時(shí)跑在 Python2 和 Python3 解釋器的代碼是可能的。最常見(jiàn)的方法是使用_future、builtins 和 six 這樣的軟件包來(lái)維護(hù)一個(gè)簡(jiǎn)單、干凈的 Python3.x 兼容代碼庫(kù),能以最小的開(kāi)銷(xiāo)同時(shí)支持Python2 和 Python3。
          python-future 是 Python2 和 Python3 之間的缺失兼容層。它提供 future 和 past 的包,能夠向前或向后移植 Python2 和 Python3 的特性。它還帶有 futurize 和 pasteurize,定制化的 2 到 3 基礎(chǔ)的腳本,可以幫助您輕松地將 Py2 或 Py3 代碼逐模塊轉(zhuǎn)換為干凈的支持 Python2 和 Python3 的Py3 風(fēng)格的代碼庫(kù)。
          請(qǐng)查看 Ed Schofield 編寫(xiě)的超贊的 Python 2-3 兼容代碼 手抄冊(cè)[6](需翻墻)。如果相比閱讀,您更喜歡視頻,可以在 PyCon AU 2014 上找到他的演講,“編寫(xiě) 2/3 兼容的代碼[7]”(需翻墻)。

          3. 寫(xiě)出美麗的代碼

          分享代碼是一個(gè)有益的嘗試。無(wú)論什么動(dòng)機(jī),如果人們發(fā)現(xiàn)您的代碼難以使用或理解,那么您的良好意圖可能沒(méi)有達(dá)到預(yù)期。幾乎每個(gè)組織都遵循開(kāi)發(fā)人員必須遵循的風(fēng)格指南,以保持一致性、易于調(diào)試和協(xié)作。Python 的禪就像一個(gè)迷你風(fēng)格的 Python 設(shè)計(jì)指南。主流的 Python 風(fēng)格指南包括:
          1. PEP-8 風(fēng)格指南

          2. Python 習(xí)語(yǔ)和效率

          3. Google Python 風(fēng)格指南

          這些準(zhǔn)則討論了如何使用:空格、逗號(hào)和大括號(hào),對(duì)象命名指南等。盡管它們?cè)谀承┣闆r下可能發(fā)生沖突,但它們都具有相同的目標(biāo) —— “清晰、可讀和可調(diào)試的代碼標(biāo)準(zhǔn)”。
          堅(jiān)持一個(gè)指南,或遵循自己的,但不要試圖跟隨與廣泛接受的標(biāo)準(zhǔn)大不相同的內(nèi)容。

          使用靜態(tài)代碼分析工具

          有許多可用的開(kāi)源工具能夠使您的代碼符合標(biāo)準(zhǔn)的風(fēng)格指南和編寫(xiě)代碼的最佳實(shí)踐。
          Pylint 是一個(gè) Python 工具,用于檢查模塊的編碼標(biāo)準(zhǔn)。Pylint 可以快速輕松地查看您的代碼是否捕捉到了 PEP-8 的精髓,因此對(duì)其他潛在用戶是“友好的”。
          它還為您提供優(yōu)良的指標(biāo)和統(tǒng)計(jì)報(bào)告,可幫助您判斷代碼質(zhì)量。您還可以通過(guò)創(chuàng)建自己的 .pylintrc 文件進(jìn)行自定義和使用。
          Pylint 不是唯一的選擇 —— 還有其他工具,如 PyChecker,PyFlakes 以及像 pep8 和 flakes8 這樣的包。
          我的建議是使用 coala,一個(gè)統(tǒng)一的靜態(tài)代碼分析框架,旨在通過(guò)單個(gè)框架提供語(yǔ)言非特定的代碼分析。Coala 支持我之前提到的所有的linting工具,并且是高度可定制的。

          正確地文檔說(shuō)明代碼

          這方面對(duì)您的代碼庫(kù)的可用性和可讀性至關(guān)重要。始終建議您盡可能廣泛地文檔說(shuō)明您的代碼,以便其他開(kāi)發(fā)人員更容易了解您的代碼。
          功能的典型內(nèi)聯(lián)文檔應(yīng)包括:
          • 該功能的一行概要。

          • 如果適用的話,提供交互示例。這些可以讓新開(kāi)發(fā)人員參考,以快速了解功能的使用和預(yù)期的輸出。您也可以使用 doctest 模塊來(lái)確保這些示例的正確性(以測(cè)試方式運(yùn)行)。請(qǐng)參閱 doctest 文檔 中的示例。

          • 參數(shù)文檔(通常一行描述參數(shù)及其在函數(shù)中的作用)

          • 返回類(lèi)型的文檔(除非您的函數(shù)沒(méi)有返回任何內(nèi)容!)

          Sphinx 是廣泛使用的用于生成和管理項(xiàng)目文檔的工具。它提供了大量方便的功能,可以減少您編寫(xiě)標(biāo)準(zhǔn)文檔的工作量。此外,您可以將文檔推送到 Read the Docs,這是最常用的托管項(xiàng)目文檔的方式。
          Hitchiker's guide to Python for documentation[8] (筆者翻譯成了中文版——Python 最佳實(shí)踐指南[9])包含一些有趣的信息,在文檔說(shuō)明代碼時(shí)可能對(duì)您有用。

          4. 提高性能

          多進(jìn)程,而不是多線程

          改進(jìn)多任務(wù)代碼的執(zhí)行時(shí)間時(shí),您可能希望利用 CPU 中的多核同時(shí)執(zhí)行多個(gè)任務(wù)。產(chǎn)生幾個(gè)線程并讓它們并發(fā)執(zhí)行可能看起來(lái)很直觀,但是由于 Python 中的全局解釋器鎖,所有的線程都是在相同的核上輪流運(yùn)行。
          為了實(shí)現(xiàn) Python 的實(shí)際并行化,您可能需要使用 Python 的 multiprocessing 模塊。另一個(gè)解決方案可以是將任務(wù)外包給:
          1. 操作系統(tǒng)(通過(guò)多進(jìn)程)

          2. 一些調(diào)用您的 Python 代碼的外部應(yīng)用程序(例如 Spark 或 Hadoop)

          3. 您的Python代碼所調(diào)用的代碼(例如,您可以讓 Python 代碼調(diào)用C函數(shù),來(lái)執(zhí)行昂貴的多線程內(nèi)容)。

          除了并行,還有其他方法可以提高您的性能。其中一些包括:
          • 使用最新版本的 Python:
            這是最直接的方法,因?yàn)樾碌母峦ǔ0▽?duì)已經(jīng)存在功能性能方面的增強(qiáng)。

          • 盡可能使用內(nèi)置函數(shù):
            這也符合 DRY 原則 —— 內(nèi)置函數(shù)由世界上一些最好的 Python 開(kāi)發(fā)人員仔細(xì)設(shè)計(jì)和審查,所以它們通常是最好的方式。

          • 考慮使用 Ctypes:
            Ctypes 提供了一個(gè)在 Python 代碼中調(diào)用 C 共享函數(shù)的接口。C 是一種更接近機(jī)器級(jí)別的語(yǔ)言,與 Python 中的類(lèi)似實(shí)現(xiàn)相比,代碼執(zhí)行速度更快。

          • 使用 Cython:
            Cython 是一種 Python 語(yǔ)言的超集,允許用戶調(diào)用 C 函數(shù)并具有靜態(tài)類(lèi)型聲明,最后生成一份更簡(jiǎn)單的最終代碼,可能會(huì)執(zhí)行得快得多。

          • 使用 PyPy:
            PyPy 是具有 JIT(即時(shí))編譯器的另一個(gè) Python 實(shí)現(xiàn),可以使您的代碼執(zhí)行更快。雖然我從未嘗試過(guò) PyPy,但它也聲稱(chēng)會(huì)減少程序的內(nèi)存消耗。像 Quora 這樣的公司實(shí)際上在生產(chǎn)環(huán)境中使用 PyPy。

          • 設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu):
            適用于各種語(yǔ)言。確保您正在為目標(biāo)使用正確的數(shù)據(jù)結(jié)構(gòu),在正確的地方聲明變量,明智地利用標(biāo)識(shí)符范圍,并在任何有意義的地方緩存結(jié)果等。

          我可以給出的一個(gè)具體的例子是:Python 通常在訪問(wèn)全局變量和解析函數(shù)地址時(shí)很慢,所以將它們分配到當(dāng)前作用域內(nèi)的一個(gè)局部變量,然后訪問(wèn)它們,速度會(huì)更快。

          5. 分析您的代碼

          通常,分析您的代碼的覆蓋度、質(zhì)量和性能是有幫助的。Python 附帶了 cProfile 模塊來(lái)幫助評(píng)估性能。它不僅給出了總運(yùn)行時(shí)間,還分別對(duì)每個(gè)函數(shù)進(jìn)行了計(jì)時(shí)。
          然后,它會(huì)告訴您每個(gè)函數(shù)調(diào)用的時(shí)間,這樣可以很容易地確定要優(yōu)化的地方。以下是cProfile 的一個(gè)示例分析:
          null
          • memory_profiler 是一個(gè)用于監(jiān)視進(jìn)程內(nèi)存消耗的Python模塊,它能對(duì) Python 程序的內(nèi)存消耗進(jìn)行逐行分析。

          • objgraph 能顯示前N個(gè)占用 Python 程序內(nèi)存的對(duì)象、在一段時(shí)間內(nèi)刪除或添加的對(duì)象以及腳本中給定對(duì)象的所有引用。

          • resource 為程序測(cè)量和控制系統(tǒng)資源使用提供了基本機(jī)制。該模塊的兩個(gè)主要用途包括限制資源分配和獲取有關(guān)資源當(dāng)前使用情況的信息。

          6. 測(cè)試和持續(xù)集成

          測(cè)試

          寫(xiě)單元測(cè)試是個(gè)好習(xí)慣。如果您認(rèn)為寫(xiě)測(cè)試不值得您努力,請(qǐng)查看此 StackOverflow 問(wèn)題[10]。最好在編碼之前或期間編寫(xiě)測(cè)試。Python 提供了unittest 模塊來(lái)為函數(shù)和類(lèi)編寫(xiě)單元測(cè)試。此外還有如下框架:
          • nose —— 可以運(yùn)行 unittest 測(cè)試,并具有較少的樣板。

          • pytest —— 也運(yùn)行unittest測(cè)試,更少的樣板,更好的報(bào)告和很多很酷,額外的功能。

          為了得到良好的比較,請(qǐng)閱讀這里[11]的介紹。
          不要忘記 doctest 模塊,它使用內(nèi)聯(lián)文檔中的交互式示例來(lái)測(cè)試源代碼。

          測(cè)量覆蓋度

          Coverage 是測(cè)量 Python 程序代碼覆蓋度的工具。它監(jiān)控您的程序,關(guān)注代碼的哪些部分已被執(zhí)行,然后分析源碼以識(shí)別可能已被執(zhí)行但沒(méi)有執(zhí)行的代碼。
          覆蓋度測(cè)量通常用于測(cè)量測(cè)試的有效性。它可以顯示您的代碼的哪些部分被測(cè)試執(zhí)行了,哪些沒(méi)有。通常建議有 100% 的分支覆蓋度,這意味著您的測(cè)試應(yīng)該能夠執(zhí)行和驗(yàn)證項(xiàng)目的每個(gè)分支的輸出。

          持續(xù)集成

          從一開(kāi)始就為您的項(xiàng)目配置 CI 系統(tǒng),對(duì)于您的項(xiàng)目來(lái)說(shuō)可以非常有用。您可以使用 CI 服務(wù)輕松測(cè)試代碼庫(kù)的各個(gè)方面。CI 中的一些典型檢查包括:
          • 在現(xiàn)實(shí)環(huán)境中運(yùn)行測(cè)試。有些情況下,測(cè)試在某些架構(gòu)上通過(guò),而在其他架構(gòu)上失敗。CI 服務(wù)可以讓您在不同的系統(tǒng)架構(gòu)上運(yùn)行測(cè)試。

          • 對(duì)您的代碼庫(kù)執(zhí)行覆蓋度約束。

          • 構(gòu)建和部署您的代碼到生產(chǎn)環(huán)境(您可以在不同的平臺(tái)上這樣做)

          現(xiàn)今有一些 CI 服務(wù):一些最受歡迎的有Travis、Circle(適用于OSX和Linux)和Appveyor(適用于Windows)。根據(jù)我最初的使用,像 Semaphore CI 這樣的新興產(chǎn)品看起來(lái)是可靠的。Gitlab(另一個(gè)Git存儲(chǔ)庫(kù)管理平臺(tái),如 Github)也支持 CI,不過(guò)如同其他服務(wù)一樣,您需要明確配置它。

          References

          [1] https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/
          [2] https://stackoverflow.com/questions/5082452/string-formatting-vs-format
          [3] https://stackoverflow.com/questions/472000/usage-of-slots
          [4] https://chase-seibert.github.io/blog/2013/08/03/diagnosing-memory-leaks-python.html
          [5] http://deeplearning.net/software/theano/tutorial/python-memory-management.html
          [6] http://python-future.org/compatible_idioms.html
          [7] https://www.youtube.com/watch?v=KOqk8j11aAI&t=10m14s
          [8] https://docs.python-guide.org/writing/documentation/
          [9] https://pythonguidecn.readthedocs.io/zh/latest/
          [10] https://stackoverflow.com/questions/67299/is-unit-testing-worth-the-effort
          [11] https://pythontesting.net/start-here/
          加微信送《Python知識(shí)點(diǎn)100題PDF》

          pk哥個(gè)人微信


          添加pk哥個(gè)人微信即送Python資料


          Python知識(shí)點(diǎn)100題的PDF

          Python相關(guān)的電子書(shū)10本


          記得備注:“100題”




          往期推薦
          01

          公眾號(hào)所有文章匯總導(dǎo)航(2-10更新)

          02

          終于,我用爬蟲(chóng)批量保存了P站的靚圖

          03

          求你了,別再用 pip 那烏龜?shù)乃俣热グ惭b庫(kù)了!


          點(diǎn)擊閱讀原文查看pk哥原創(chuàng)視頻

          我就知道你“在看”

          瀏覽 63
          點(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>
                  人人爽人人操人人爱 | 国产成人高清 | 久操成人网 | 天天久久AV | 中日韩成人片 |