Cython 估計(jì)很多人都聽說(shuō)過(guò),它是用來(lái)對(duì) Python 進(jìn)行加速的。如果你在使用 Python 編程時(shí),有過(guò)如下想法,那么 Cython 非常適合你。
- 因?yàn)槟承┬枨髮?dǎo)致不得不編寫一些多重嵌套的循環(huán),而這些循環(huán)如果用 C 語(yǔ)言來(lái)實(shí)現(xiàn)會(huì)快上百倍,但是不熟悉 C 或者不知道 Python 如何與 C 進(jìn)行交互;
- 因?yàn)?Python 解釋器的性能原因,如果將 CPython 解釋器換成 PyPy,或者干脆換一門語(yǔ)言,比如 Rust,將會(huì)得到明顯的性能提升,可是換不得。因?yàn)槟愕捻?xiàng)目組規(guī)定只能使用 Python 語(yǔ)言,解釋器只能是 CPython;
- Python 是一門動(dòng)態(tài)語(yǔ)言,但你希望至少在數(shù)字計(jì)算方面,能夠加入可選的靜態(tài)類型,這樣可以極大地加速運(yùn)算效果。因?yàn)閱渭兊臄?shù)字相加不太需要所謂的動(dòng)態(tài)性,尤其是當(dāng)你的程序中出現(xiàn)了大量的計(jì)算邏輯時(shí);
- 對(duì)于一些計(jì)算密集型的部分,你希望能夠?qū)懗鲆恍╂敲?Numpy, Scipy, Pandas 的算法;
- 你有一些已經(jīng)用 C、C++ 實(shí)現(xiàn)的庫(kù),你想直接在 Python 內(nèi)部更好地調(diào)用它們,并且不使用 ctypes、cffi 等模塊;
- 也許你聽說(shuō)過(guò) Python 和 C 可以無(wú)縫結(jié)合,通過(guò) C 來(lái)為 Python 編寫擴(kuò)展模塊,將 Python 代碼中性能關(guān)鍵的部分使用 C 進(jìn)行重寫,來(lái)達(dá)到提升性能的效果。但是這需要你對(duì) Python 解釋器有很深的了解,熟悉底層的 Python/C API,而這是一件非常痛苦的事情;
如果你有過(guò)上面的一些想法,那么證明你的 Python 水平是很優(yōu)秀的,然而這些問(wèn)題總歸是要解決的,于是 Cython 便閃亮登場(chǎng)了。注意:Cython 并不是一個(gè)什么實(shí)驗(yàn)性的項(xiàng)目,它出現(xiàn)的時(shí)間已經(jīng)不短了,并且在生產(chǎn)環(huán)境中久經(jīng)考驗(yàn),我們完全是有理由學(xué)習(xí)它的。
Cython 是什么?
關(guān)于 Cython,我們必須要清楚兩件事:
- Cython 是一門編程語(yǔ)言,它將 C 和 C++ 的靜態(tài)類型系統(tǒng)融合在了 Python 身上。Cython 源文件的后綴是 .pyx,它是 Python 的一個(gè)超集,語(yǔ)法是 Python 語(yǔ)法和 C 語(yǔ)法的混血。當(dāng)然我們說(shuō)它是 Python 的一個(gè)超集,因此你寫純 Python 代碼也是可以的。
- 當(dāng)我們編寫完 Cython 代碼時(shí),需要先將 Cython 代碼翻譯成高效的 C 代碼,然后再將 C 代碼編譯成 Python 的擴(kuò)展模塊。
在早期,編寫 Python 擴(kuò)展都是拿 C 去寫,但是這對(duì)開發(fā)者有兩個(gè)硬性要求:一個(gè)是熟悉 C,另一個(gè)是要熟悉解釋器提供的 C API,這對(duì)開發(fā)者是一個(gè)非常大的挑戰(zhàn)。此外,拿 C 編寫代碼,開發(fā)效率也非常低。而 Cython 的出現(xiàn)則解決了這一點(diǎn),Cython 和 Python 的語(yǔ)法非常相似,我們只需要編寫 Cython 代碼,然后再由 Cython 編譯器將 Cython 代碼翻譯成 C 代碼即可。所以從這個(gè)角度上說(shuō),拿 C 寫擴(kuò)展和拿 Cython 寫擴(kuò)展是等價(jià)的。
至于如何將 Cython 代碼翻譯成 C 代碼,則依賴于相應(yīng)的編譯器,這個(gè)編譯器本質(zhì)上就是 Python 的一個(gè)第三方模塊。它就相當(dāng)于是一個(gè)翻譯官,既然用 C 寫擴(kuò)展是一件痛苦的事情,那就拿 Cython 去寫,寫完了再幫你翻譯成 C。
因此 Cython 的強(qiáng)大之處就在于它將 Python 和 C 結(jié)合了起來(lái),可以讓你像寫 Python 代碼一樣的同時(shí)還可以獲得 C 的高效率。所以我們看到 Cython 相當(dāng)于是高級(jí)語(yǔ)言 Python 和低級(jí)語(yǔ)言 C 之間的一個(gè)融合,因此有人也稱 Cython 是 "克里奧爾編程語(yǔ)言"(creole programming language)。
為什么要有 Cython?
Python 和 C 語(yǔ)言大相徑庭,為什么要將它們?nèi)诤显谝黄鹉兀看鸢甘牵阂驗(yàn)檫@兩者并不是對(duì)立的,而是互補(bǔ)的。
Python 是高階語(yǔ)言、動(dòng)態(tài)、易于學(xué)習(xí),并且靈活。但這些優(yōu)秀的特性是需要付出代價(jià)的,因?yàn)?Python 的動(dòng)態(tài)性、以及它是解釋型語(yǔ)言,導(dǎo)致其運(yùn)行效率比靜態(tài)編譯型語(yǔ)言慢了好幾個(gè)數(shù)量級(jí)。
而 C 語(yǔ)言是最古老的靜態(tài)編譯型語(yǔ)言之一,并且至今也被廣泛使用。從時(shí)間來(lái)算的話,其編譯器已有將近半個(gè)世紀(jì)的歷史,在性能上做了足夠的優(yōu)化,因此 C 語(yǔ)言是非常低級(jí)、同時(shí)又非常強(qiáng)大的。然而不同于 Python 的是,C 語(yǔ)言沒(méi)有提供保護(hù)措施(沒(méi)有 GC、容易內(nèi)存泄露),以及使用起來(lái)很不方便。
所以兩個(gè)語(yǔ)言都是主流語(yǔ)言,只是特性不同使得它們被應(yīng)用在了不同的領(lǐng)域。而 Cython 的美麗之處就在于:它將 Python 語(yǔ)言豐富的表達(dá)能力、動(dòng)態(tài)機(jī)制和 C 語(yǔ)言的高性能匯聚在了一起,并且代碼寫起來(lái)仍然像寫 Python 一樣。
注意:除了極少數(shù)的例外,Python 代碼(2.x和3.x版本)已經(jīng)是有效的 Cython 代碼,因?yàn)?Cython 可以看成是 Python 的超集。并且 Cython 在 Python 語(yǔ)言的基礎(chǔ)上添加了一些少量的關(guān)鍵字來(lái)更好地開發(fā) C 的類型系統(tǒng),從而允許 Cython 編譯器生成高效的 C 代碼。如果你已經(jīng)知道 Python 并且對(duì) C 或 C++ 有一定的基礎(chǔ)了解,那么你可以直接學(xué)習(xí) Cython,無(wú)需再學(xué)習(xí)其它的接口語(yǔ)言。
另外,我們其實(shí)可以將 Cython 當(dāng)成兩個(gè)身份來(lái)看待:
- 如果將 Cython 翻譯成 C,那么可以看成 Cython 的 '陰';
- 如果將 Python 作為膠水連接 C 或者 C++,那么可以看成是 Cython 的 '陽(yáng)'。
我們可以從需要高性能的 Python 代碼開始,也可以從需要一個(gè)優(yōu)化 Python 接口的 C、C++ 開始,而我們這里是為了學(xué)習(xí) Cython,因此顯然是選擇前者。為了加速 Python 代碼,Cython 將使用可選的靜態(tài)類型聲明并通過(guò)算法來(lái)實(shí)現(xiàn)大量的性能提升,尤其是靜態(tài)類型系統(tǒng),這是實(shí)現(xiàn)高性能的關(guān)鍵。
Cython 和 CPython 的區(qū)別?
關(guān)于 Cython,最讓人困惑的就是它和 CPython 之間的關(guān)系,但是需要強(qiáng)調(diào)的是這兩者是完全不同的。
首先 Python 是一門語(yǔ)言,它有自己的語(yǔ)法規(guī)則,我們按照 Python 語(yǔ)言規(guī)定的語(yǔ)法規(guī)則編寫的代碼就是 Python 源代碼。但是源代碼只是一個(gè)或多個(gè)普通的文本文件,我們需要使用 Python 語(yǔ)言對(duì)應(yīng)的解釋器來(lái)執(zhí)行它。
而 Python 解釋器也會(huì)按照同樣的語(yǔ)法規(guī)則來(lái)對(duì)我們編寫的 Python 源代碼進(jìn)行分詞、語(yǔ)法解析等等,如果我們編寫的代碼不符合 Python 的語(yǔ)法規(guī)則,那么會(huì)報(bào)出語(yǔ)法錯(cuò)誤,也就是 SyntaxError。如果符合語(yǔ)法規(guī)范的話,那么會(huì)順利地生成抽象語(yǔ)法樹(Abstract Syntax Tree,簡(jiǎn)稱 AST),然后將 AST 編譯成指令集合,也就是所謂的字節(jié)碼(bytes code),最后再執(zhí)行字節(jié)碼。
所以 Python 源代碼是需要 Python 解釋器來(lái)操作的,如果我們想做一些事情的話,光寫成源代碼是不行的,必須要由 Python 解釋器將我們的代碼解釋成機(jī)器可以識(shí)別的指令進(jìn)行執(zhí)行才可以。而 CPython 正是 Python 語(yǔ)言對(duì)應(yīng)的解釋器,并且它也是官方實(shí)現(xiàn)的標(biāo)準(zhǔn)解釋器,同時(shí)還是使用最廣泛的一種解釋器?;旧衔覀兪褂玫慕忉屍鞫际?CPython,也就是從官網(wǎng)下載、然后安裝之后所得到的。
標(biāo)準(zhǔn)解釋器 CPython 是由 C 語(yǔ)言實(shí)現(xiàn)的,除了 CPython 之外還有 Jython(java實(shí)現(xiàn)的 Python 解釋器)、PyPy(Python 語(yǔ)言實(shí)現(xiàn)的 Python 解釋器)等等??傊O(shè)計(jì)出一門語(yǔ)言,還要有相應(yīng)的解釋器才可以;至于編譯型語(yǔ)言,則是對(duì)應(yīng)的編譯器。
最后重點(diǎn)來(lái)了,我們說(shuō) CPython 解釋器是由 C 實(shí)現(xiàn)的,它給 Python 語(yǔ)言提供了 C 級(jí)別的接口,也就是熟知的 Python/C API。比如:Python 的列表,底層對(duì)應(yīng)的是 PyListObject;字典則對(duì)應(yīng) PyDictObject,等等等等。
所以當(dāng)我們?cè)?Python 中創(chuàng)建一個(gè)列表,那么 CPython 在執(zhí)行的時(shí)候,就會(huì)在底層創(chuàng)建一個(gè) PyListObject。因?yàn)?CPython 是用 C 來(lái)實(shí)現(xiàn)的,最終肯定是將 Python 代碼翻譯成 C 級(jí)別的代碼,然后再變成機(jī)器碼交給 CPU 執(zhí)行。
而 Cython 也是如此,Cython 代碼也要被翻譯成 C 代碼,然后 C 代碼再變成擴(kuò)展(本質(zhì)上也是機(jī)器碼),導(dǎo)入之后直接執(zhí)行,而無(wú)需動(dòng)態(tài)解釋。因此 Cython 是一門語(yǔ)言,它并不是Python 解釋器的另一種實(shí)現(xiàn),它的地位和 CPython 不是等價(jià)的,不過(guò)和 Python 是平級(jí)的。
總結(jié):Cython 是一門語(yǔ)言,可以通過(guò) Cython 源代碼生成高效的 C 代碼,再將 C 代碼編譯成擴(kuò)展模塊,同樣需要 CPython 來(lái)進(jìn)行調(diào)用。
審核編輯:符乾江
-
源代碼
+關(guān)注
關(guān)注
96文章
2953瀏覽量
68409 -
python
+關(guān)注
關(guān)注
56文章
4827瀏覽量
86802
發(fā)布評(píng)論請(qǐng)先 登錄
ADS7945兩個(gè)通道之間會(huì)有干擾,為什么?
為什么ADS1255每次轉(zhuǎn)換的數(shù)據(jù)會(huì)有波動(dòng)?
為什么MOS管內(nèi)會(huì)有體二極管,它是怎么來(lái)的有什么作用

評(píng)論