「一百萬行 Python 代碼對任何人都足夠了」

csdn 發佈 2020-01-06T22:14:39+00:00

作者 | Jake Edge譯者 | Kolen出品 | AI科技大本營(ID: rgznai100)程式語言通常對其操作過程的各個方面都有或明或暗的限制。

作者 | Jake Edge

譯者 | Kolen

出品 | AI科技大本營(ID: rgznai100)

程式語言通常對其操作過程的各個方面都有或明或暗的限制。諸如標識符的最大長度或變量可以存儲的值的範圍之類的事情,這些是相當明顯的例子,但是還有其他一些例子,其中許多是語言設計者未指明的,並且出現在各種實際應用語言編程的過程中。

這種模稜兩可的限制可能會帶來嚴重後果,因此在Python中確定各種各樣的限制是「Python-dev」郵件列表(譯者註:「Python-dev」是Python開發者社區的一個子欄目)上正在持續進行的討論目標。

Mark Shannon發表了一項「對Python程序的各個方面(比如每個模塊的代碼行)實行一百萬行限制」的提案。一百萬看起來像是一個任意的數字(事實上也是如此),但他提出這一想法還是考慮到這個數字比較容易讓人記住,因此可以使得程式設計師在對程式語言添加的限制而感到疑惑時無需查閱參考。

儘管有如此提案的想法,Python虛擬機存儲的某些值(例如行號)是32位值,這顯然固化了自身的限制,但是這樣的值可能會浪費絕大多數一直沒有關閉的Python程序的存儲空間。除此之外,溢出這些32位值可能會導致安全性和其他類型問題的出現。

正如Shannon指出的,21位可以容納的範圍是從-1,000,000到1,000,000,其中三個值可以打包成一個64位字。「內存訪問通常是現代CPU性能的一個限制因素。在ALU使用量適度增加(用於移位和屏蔽)的情況下,更好地打包數據結構可以增強局部性並減少內存[帶寬]。」 他還指出,基於堆棧框架對象,代碼對象和對象本身的數據結構可以通過這種打包的形式而受益。「還有一種潛在的更有效的指令格式,可以加快解釋器的分派速度。」

他提議將限制用於以下Python程序的七個不同方面:

  • 模塊中的原始碼行數

  • 代碼對象中字節碼指令的數量

  • 代碼對象的局部變量和堆棧使用量的總和

  • 代碼對象中不同名稱的數量

  • 代碼對象中的常量數

  • 正在運行的解釋器中的類別數

  • 正在運行的解釋器中的實時協同程序數

他還解決了「這不又是類似於『640K對任何人來說應該已經足夠了』?」的問題,這是一個當提出任意限制時,人們會立即想到的問題。他指出,Java虛擬機(JVM)將許多程序元素限制為65535(適合16位);這可能會產生限制,但主要是針對程序生成器,而不是手工編寫的代碼。他對Python提出的限制遠不止於此,他認為這不會成為人為生成代碼的真正障礙。他說到,「雖然生成的代碼可能會超出限制,但代碼生成器很容易修改其輸出以符合標準。」

社區成員的一些回應

他為一些限制提供了簡短的理由,但許多在這篇文章中發表過評論的人關心的是這些限制究竟能提供多少好處。Chris Angelico問Shannon是否做過任何評估,來看看會有多大的影響。Steven D'Aprano同意獲得內存和安全性好處的前提,但他期望Python開發人員對預期的速度提高抱有「一點期望」。Steve Dower認為,總體的思路並非不合理,儘管他也有一些擔憂:

「出於許多原因,選擇小於2**32的任意限制肯定更安全,而且不太可能影響實際使用。我們已經有了一些低於10**6的實際限制(例如if/else深度和遞歸限制)。」

「也就是說,我真的不想影響邊緣情況的使用,而且我非常熟悉其他任意限制的例子(任何文件系統都不需要超過260個字符的路徑,對吧?:o))。」

Dower引用Windows MAX PATH值,該值將Win32 API中的路徑名限制為最多260個字符。他認為,雖然每個模塊的行數限制「感覺是最隨意的」,但提出的幾個限制似乎確實合理。注釋和空行肯定會超過限制,這讓他停頓思考了一下。他說,「『正在運行的解釋器中的類』」的有關限制有點令人擔憂,但可能有辦法處理超出此限制的程序,同時仍能獲得它帶來的所有收益:「即使沒有其他的PEP,這裡的好處似乎還是值得的。」

但Rhodri James認為,像這樣提出的限制最終將成為某一部分人的問題;他也反對將計數打包成更小的比特寬度的想法,因為每次訪問的掩蔽和移位效率均較低。Gregory P. Smith通常贊成限制,但他擔心代碼生成會與限制發生衝突;他指出,JVM限制在Android領域是一個大問題。線程中的其他人也指出JVM限制是有問題的。

Guido van Rossum對這個想法發表了一些的看法。他對所要解決的問題有些疑惑,並表示懷疑,例如,以20位而不是32位表示行號確實會大大提高效率。他擔心「給生成代碼帶來麻煩的現有的(或偶然出現的)限制」。但他還指出,現有的CPython解析器只限於100個嵌套括號級別(以及可能還有嵌套的縮進級別),而且他沒有聽到過任何相關的吐槽。

Oscar Benjamin提到了一個具有一百萬行的文件的真實案例。這是一個SymPy的測試文件,該文件使Python 3.6解釋器崩潰了(儘管在3.7.1中已修復)。實際的測試大約只有3000行,但是pytest框架將其重寫為一個包含一百萬行的文件。班傑明還指出,一百萬個字節碼指令的限制更加嚴格。

Jim J. Jewett說,應該在語言本身的限制和CPython實現的限制之間進行區分。他指出「記錄CPython選擇實施的限制(特別是當前的選擇),有很大的價值。」 但是,對語言本身來說,將限制設置得太高可能會遺漏MicroPython之類的實現。

「更改CPython(或至少在默認模式下為CPython)所支持的限制或其字節碼格式可能很有價值,但應將其清楚地表述為CPython實現PEP(或字節碼PEP),而不是一個語言更改PEP。」

PEP 611

Shannon接受了反饋,並將其反映在PEP611(「百萬限制」)中。這就引出了另一個話題,在這個話題中,人們呼籲對變化進行某種基準測試,以便合理地評估變化。Barry Warsaw還說「對於你是建議使用Python作為語言限制,還是建議使用CPython作為實現限制,還缺乏明確性」。如果限制是針對語言的,「那麼PEP需要聲明,並且應該請求其他實現開發人員的反饋」。

幾天後,Shannon要求評論人士更準確地表達他們的關心的問題。任一選擇都有相關的成本,但僅簡單地說明對更高限額的偏好並不完全有幫助:

「僅僅說你想要更大的限制是沒有意義的。如果不需要為任意大的限制付出任何代價,那麼我就不會首先提出PEP。」

「更高限額的成本由所有人承擔,但收益卻很少,請注意這一點。」

Angelico再次要求提供具體數字,但是Shannon說,性能的提高很難量化:「 鑒於將啟用的潛在優化數量無限,因此在數字上加一個數字有點困難:) 」。不出所料,這種回答並不完全受歡迎。但是部分問題可能是Shannon將潛在的優化部分地看作是限制所帶來的其他優勢的副產品。正如Nathaniel Smith所說:

「Mark,可能你想重新構造PEP,使其更像是『這對正確性有好處,並且可以為解釋器提供可靠的推理,這有很多好處(並且速度最終可能是其中之一)』我的印象是,你將加速視為次要動機,而其他人則感覺到加速是整個動機,因此,一種或多種方式會使人們感到困惑。」

Shannon說,做出這種改變當然需要理由,但他認為,目前的限制(或缺乏限制)是由於「歷史事故和/或實施細節」造成的,這理由似乎很空洞。Van Rossum對這一說法持異議:

「哇哦,在現狀中沒有局限性(除了通過可用的內存間接地限制各種事物之外)最有可能是有意決策的結果。『沒有任意限制』是Python最初設計理念的一部分。我們並非總是成功(想到樹的深度和調用遞歸深度),但這絕對是哲學。」

「你非常需要證明為什麼我們現在應該改變。「無數的潛在優化」並沒有消除它。「

Shannon回答說,這可能是語言哲學的一部分,「但實際上Python有很多限制。」例如,他指出,在一個代碼對象中有231條以上的指令將導致CPython崩潰;這是一個可以修復的錯誤,但這類問題可能很難測試和查找。

「顯式的限制更容易測試。超出限制的代碼是否會以預期的方式失敗並且恰好在限制以下的代碼可以正常工作?」

「我想要的是允許更有效地使用資源,而又不會出現較低或未指定的限制。有限的機器上總會有一些限制。如果未指定它們,它們仍然存在,我們只是不知道它們是什麼或它們如何表現出來。」

Van Rossum特別提出了對類數和協同程序數的限制,因為這是有問題的。更改對象標頭(這是對類的限制所允許的一件事)是對C API的更改,因此他認為應該單獨討論。協同程序「只是另一個Python對象,沒有與之相關聯的操作資源」,因此他不明白為什麼要專門針對它們。其他人同意協同工作,並提出了可能需要超過一百萬個應用程式的建議。這些反對意見導致Shannon放棄了PEP中的協同程序,因為「限制協同程序的理由可能是最弱的」。

指導委員會的想法

在PEP上, Python指導委員會(可能是其最後一次正式行動之一,因為在12月16日選舉產生了新的理事會)。華沙表示,已經在12月10日的會議上進行了討論。理事會建議將PEP分為兩部分,一部分適用於該語言的所有實現,並將提供在運行時確定限制的方法;另一部分是針對CPython的特定實現,但對該實現有限制。此外,「我們鼓勵PEP的作者和支持者收集實際的績效數據,以幫助我們評估PEP是否是一個好主意。」

Shannon仍然懷疑用「少量優化」來判斷PEP是正確。不可能對所有無限可能的優化都加上數字,但也「不可能完美地預測哪些限制可能限制未來的可能的應用」。不過,他也同意,提出受限制的示例優化和應用程式將很有用。

在另一條主題中,Shannon要求提供反饋意見和建議,並提供具體細節。他還想知道,他選擇一個數字作為限制(主要是作為記憶的輔助手段)的想法是否重要。又一些人認為,由於各種原因選擇一個數字是不合理的。正如D' Aprano所說的那樣,沒有人需要記住這些限制,因為它們無論如何都應該很少會受到限制,而且應該有一種在運行時獲得它們的方法。除此之外,對於嵌套括號、遞歸深度等現在還沒有、將來也不會用到一百萬行。

Paul Moore也認為單一的限制值並不重要,儘管他贊成為任何限制選擇整數,而不是根據實現細節進行選擇。他可能還總結了大多數人是如何看待這個想法的:

「我的觀點是,我反對任何沒有顯示出好處的限制。我不在乎有多少好處,儘管我希望限制的影響與好處的水平保持一致。實際上,這意味著我認為這個提議是落伍的。我更希望這項提案的定義是『如果我們強加這樣或那樣的一個限制,我們將能得到一個收益』。」

這就是現在的情況。指導委員會似乎對這個一百萬行代碼的限制很感興趣,因為它在初期就接受了PEP,儘管該委員會的利益可能與Shannon的觀點並不完全一致。然而,定義不清的限制,以及如果超過這些限制會發生什麼的不明確語義,將對任何人都沒有什麼好處。對CPython的規範和對整個語言的其他API進行一些收緊將是很好的一步。它可能允許那些感興趣的人在CPython的實驗分支中調整值,以測試一些優化可能性。

原文連結:https://lwn.net/Articles/807218/

關鍵字: