事件回顧
就在不久前,Python核心開發(fā)者Pablo在郵件中宣布,由于一些重要的性能Bug和崩潰問題,預(yù)計(jì)在10月底發(fā)布的Python 3.11穩(wěn)定版本可能要推遲到12月。
圖片來源@郵件截圖
此事引來了不少人的關(guān)注。Python是當(dāng)今最流行的編程語言之一,StackOverflow 2022 開發(fā)者報(bào)告顯示,對初學(xué)者而言,HTML/CSS、Javascript和Python幾乎并列為最常用的語言,而在TIOBE發(fā)布的2022年6月編程語言排行上,Python語言則排名第一,因而Python語言新版本的發(fā)布,通常很受關(guān)注。
自2008年12月3日Python3.0發(fā)布以來,Python官方計(jì)劃每年發(fā)布一個(gè)新版本,每次增加兩三種新語法。雖然實(shí)際情況并沒有嚴(yán)格按照計(jì)劃實(shí)現(xiàn),但自3.8版本以后,Python的發(fā)版節(jié)奏基本有規(guī)律可循:在每個(gè)版本發(fā)布前,都有17個(gè)月的開發(fā)周期,在此期間要進(jìn)行持續(xù)的開發(fā)測試;測試期間,首先會發(fā)布alpha版本,等到4月份再發(fā)布beta版本,直到10月左右,發(fā)布最終的正式版本。Python 3歷次版本發(fā)布時(shí)間
本來,計(jì)劃今年發(fā)布的3.11版本也是按照這個(gè)節(jié)奏進(jìn)行,但這次,3.11版本的發(fā)布會成為一個(gè)例外。值得一提的是,在郵件的最后,Pablo對能否在12月發(fā)布穩(wěn)定版本也沒有信心。
圖片來源@郵件截圖
Python 3.11期待已久
雖然Python簡單易學(xué),但其運(yùn)行速度之慢歷來被詬?。ㄔ诿看蔚木幊陶Z言速度競賽中,Python的名次通常都墊底),因而很多開發(fā)者期待這門語言的性能有所提升。
也許正是這個(gè)原因,Python創(chuàng)始人Guido van Rossum重新出山后,在2021年P(guān)ython語言峰會上作了一場《Making CPython Faster》的分享,他表示,自己已經(jīng)投入了“香農(nóng)計(jì)劃”(“Shannon Plan”,得名于提出者M(jìn)ark Shannon),期望花4年時(shí)間把Python提速5倍,即每年1.5倍,其中近期計(jì)劃是在Python 3.11 版本中實(shí)現(xiàn)至少提速1倍。
根據(jù)7月6日發(fā)布的Python 3.11.0b3來看,在Ubuntu Linux上使用GCC編譯,且使用pyperformance基準(zhǔn)套件測量時(shí),CPython 3.11比CPython 3.10平均快25%。根據(jù)工作負(fù)載的不同,CPython 3.11的提速介于10% 到 60% 之間。
圖片來源@文檔截圖
此外,由于Python3.11是一個(gè)較大版本更新,根據(jù)已有的測試結(jié)果看,其在更精確的錯(cuò)誤提示、類型特性、用except*處理多個(gè)異常、Zero-cost異常、改進(jìn)類型(包括改進(jìn)類型、任意的字符串字面類型、數(shù)據(jù)類轉(zhuǎn)換、標(biāo)準(zhǔn)庫中的 TOML 只讀支持等)也有改進(jìn),這些也是開發(fā)者比較期待的新功能。
如何給Python“踩踩油門”
此前Python為何會給大家留下運(yùn)行速度慢的印象呢?通常有三種解釋。
第一種解釋為Python是動態(tài)性語言不是靜態(tài)性語言。
對C等靜態(tài)語言來說,編譯器在聲明變量的時(shí)候就知道其類型了;而對Python來說,Python程序在執(zhí)行的時(shí)候,編譯器不知道變量的類型,只知道它是一個(gè)對象。這意味著,即使是a+b這樣的簡單二元運(yùn)算,由于變量a和b本身都沒有類型,而它們的值有類型,Python執(zhí)行起來也很“麻煩”:在相“加”之前,必須先判斷類型。
第二種解釋是Python是解釋性語言而不是編譯性語言。
像C、C++、Rust這些語言是直接編譯成機(jī)器碼運(yùn)行,是編譯型語言;Python的運(yùn)行過程是虛擬機(jī)讀入Python代碼(文本),詞法分析,編譯成虛擬機(jī)認(rèn)識的opcode,然后虛擬機(jī)解釋opcode執(zhí)行,而最后這一步“虛擬機(jī)解釋opcode執(zhí)行”是比較費(fèi)時(shí)間的。
第三種解釋認(rèn)為,是全局解釋器鎖(GIL,Global Interpreter Lock)的原因。
現(xiàn)代計(jì)算機(jī)處理器一般都會有多核,甚至有些服務(wù)器有多個(gè)處理器。所以操作系統(tǒng)抽象出 Thread,可以在一個(gè)進(jìn)程中spawn出多個(gè)Thread,讓這些Thread在多個(gè)核上面同時(shí)運(yùn)行,發(fā)揮處理器的最大效率。
而Python自帶垃圾回收程序,且選擇的實(shí)現(xiàn)垃圾回收機(jī)制是引用計(jì)數(shù)+分代回收,并以引用計(jì)數(shù)為主。在多線程情況下,大家一起運(yùn)行,引用計(jì)數(shù)多個(gè)線程一起操作,為保證不發(fā)生線程不安全的事情,多個(gè)線程操作同一個(gè)對象需要加鎖。這就是GIL,只不過這個(gè)鎖的粒度太大了,整個(gè)Python解釋器全局只有一個(gè)Thread可以運(yùn)行。
換句話說,無論電腦CPU有多少核,對Python來說,它只用一個(gè)核。這三種解釋都有一定道理,理論上Python提速可以從以上三個(gè)方向進(jìn)行突破。從最近Python團(tuán)隊(duì)公布的情況看,Python 3.11 的性能改進(jìn)主要集中在更快的啟動和更快的運(yùn)行時(shí),這些優(yōu)化大部分來自于PEP 659(一種自適應(yīng)解釋器),它運(yùn)作思路跟JIT有點(diǎn)相似,都是識別熱點(diǎn)代碼,但自適應(yīng)解釋器的工作范圍無法脫離字節(jié)碼。
圖片來源@文檔截圖
3.11為何會推遲發(fā)布
從Pablo在郵件中公布的信息看,Python 3.11推遲發(fā)布主要是由于出現(xiàn)很多“影響發(fā)布”的bug。
圖片來源@GitHub截圖
雖然bug的細(xì)節(jié)還有待進(jìn)一步發(fā)掘,但根據(jù)現(xiàn)有情況猜測,問題可能在以下的兩方面。
一是C擴(kuò)展的問題。CPython與C的簡單接口是主要優(yōu)勢,而與C擴(kuò)展的不兼容性則是一大槽點(diǎn)。CPython團(tuán)隊(duì)在CPython 3.11中所做的優(yōu)化工作在很大程度上忽略了擴(kuò)展模塊的問題,對此,團(tuán)隊(duì)領(lǐng)導(dǎo)者香農(nóng)表示,團(tuán)隊(duì)正在開辟將低級函數(shù)API暴露給虛擬機(jī)的可能性,以盡可能地減少Python代碼和C代碼。
二是前面反復(fù)提到的提速問題。Python創(chuàng)始人Guido van Rossum預(yù)期Python 3.11版本中實(shí)現(xiàn)至少提速1倍,而目前Python 3.11.0b3比Python 3.10平均只快了25%,跟理想目標(biāo)還有不小的差距。
另外,Meta開發(fā)人員Sam Gross在今年的Python語言峰會上,向與會者介紹了nogil的情況,這是一個(gè)專注于移除GIL的項(xiàng)目,據(jù)Python基金會介紹,Gross 將發(fā)明一種新型鎖,如果順利的話,這個(gè)新鎖很可能在Python 3.12版本亮相。
Sam Gross的提案雖然讓很多開發(fā)者興奮,但與Python團(tuán)隊(duì)的現(xiàn)在工作基于PEP 659進(jìn)行優(yōu)化的工作會產(chǎn)生沖突:畢竟CPython團(tuán)隊(duì)已實(shí)施的優(yōu)化,很大一部分都基于GIL仍存在的前提。如果采用Sam Gross的提案,在Python 3.12去除GIL,那么Python 3.11就要做出不小的改動,也許,這也是導(dǎo)致Python 3.11延期的重要原因。
總之,考慮到當(dāng)前Python在編程語言界“如日中天”的地位,Python 3.11又志在克服其最大的缺點(diǎn),Python的未來還是很值得期待的。
參考鏈接:
https://mail.python.org/archives/list/python-dev@python.org/thread/3JWVCSBPBFWY5ZWSJ7RYB6FS5NIMCEOY/
https://docs.python.org/zh-cn/3.11/whatsnew/3.11.html#faster-cpython