一、Python運(yùn)行速度慢的原因
1、python是解釋性語(yǔ)言
python是一個(gè)解釋性的動(dòng)態(tài)類(lèi)型腳本語(yǔ)言,解釋性語(yǔ)言的特點(diǎn)就是程序只有在執(zhí)行的時(shí)候才會(huì)去編譯,也就是說(shuō)邊執(zhí)行邊進(jìn)行編譯。而Java、C這種編譯性的語(yǔ)言在程序執(zhí)行之前就已經(jīng)將其編譯為機(jī)器可讀的代碼了,自然運(yùn)行速度快。而且python程序在沒(méi)有運(yùn)行之前都是能夠直接以源碼的形式存在的,這也是它能夠跨平臺(tái)運(yùn)行的主要原因,但是在沒(méi)有經(jīng)過(guò)編譯的python運(yùn)行速度上就會(huì)有所降低。
2、Python是動(dòng)態(tài)語(yǔ)言
動(dòng)態(tài)語(yǔ)言是一類(lèi)在運(yùn)行時(shí)可以改變其結(jié)構(gòu)的語(yǔ)言,如新的函數(shù)、對(duì)象、代碼可以被引入,已有的函數(shù)可以被刪除或其他結(jié)構(gòu)上的變化等,該類(lèi)語(yǔ)言更具有活性,但是不可避免的因?yàn)檫\(yùn)行時(shí)的不確定性也影響運(yùn)行效率。數(shù)據(jù)的比較和轉(zhuǎn)換類(lèi)型的開(kāi)銷(xiāo)很大,每次讀取、寫(xiě)入或引用一個(gè)變量,都要檢查類(lèi)型。很難優(yōu)化一種極具動(dòng)態(tài)性的語(yǔ)言。Python的許多替代語(yǔ)言之所以快得多,原因在于它們?yōu)榱诵阅茉陟`活性方面作出了犧牲。
3、Python中一切都是對(duì)象
Python是一門(mén)面向?qū)ο蟮木幊陶Z(yǔ)言,其設(shè)計(jì)理念是一切皆是對(duì)象,如數(shù)字、字符串、元組、列表、字典、函數(shù)、方法、類(lèi)、模塊等都是對(duì)象,包括代碼,每個(gè)對(duì)象都需要維護(hù)引用計(jì)數(shù),因此,增加了額外工作,影響了性能。
4、Python GIL
GIL是Python最為詬病的一點(diǎn),因?yàn)镚IL,Python中的多線程并不能真正的并發(fā),即使在單線程,GIL也會(huì)帶來(lái)很大的性能影響,因?yàn)閜ython每執(zhí)行100個(gè)opcode就會(huì)嘗試線程的切換,因此,影響Python運(yùn)行效率。
5、垃圾回收機(jī)制
Python采用標(biāo)記和分代的垃圾回收策略,每次垃圾回收的時(shí)候都會(huì)中斷正在執(zhí)行的程序,造成所謂的頓卡,影響運(yùn)行效率。
二、提升Python性能的方案
1、Cython
是Python的C語(yǔ)言擴(kuò)展,cPython是一門(mén)單獨(dú)的語(yǔ)言,專(zhuān)門(mén)用來(lái)寫(xiě)在Python里面的import用的擴(kuò)展庫(kù)。CPython跟Python語(yǔ)法基本一致,而CPython有專(zhuān)門(mén)的編譯器。據(jù)說(shuō),Cython提供了一些特性來(lái)讓代碼更高效,比如變量類(lèi)型化,這本質(zhì)上是C要求的。一些科學(xué)計(jì)算的包,如scikit-learn依賴Cython的一些特性來(lái)保持操作簡(jiǎn)潔快速。
2、Pyston
Pyston,由Dropbox資助,使用LLVM編譯器架構(gòu)來(lái)加速Python,同樣的它也使用了適時(shí)編譯。相比于PyPy,Pyston還處于早期階段,它只支持Python的部分特性。Pyston把工作分成兩個(gè)部分,一部分是語(yǔ)言的核心特性,另一部分是把性能提升到可接受的程度。Pyston距離可以在生產(chǎn)環(huán)境使用還有一段距離
3、Nuitka
是一個(gè)Python的替代品,它可以將Python代碼轉(zhuǎn)換為C++代碼,然后編譯為可執(zhí)行文件,并且通過(guò)調(diào)用Python的API的方式實(shí)現(xiàn)從解析語(yǔ)言到編譯語(yǔ)言的轉(zhuǎn)換,在轉(zhuǎn)換到C++的過(guò)程中直接使用python的解釋器,可以保證100%的語(yǔ)法兼容。
4、Numba
Numba結(jié)合了上面幾個(gè)項(xiàng)目的想法。學(xué)習(xí)了Cython,Numba也采用了部分加速的策略,只加速CPU密集型的任務(wù);同時(shí)它又學(xué)習(xí)了PyPy和Pyston,通過(guò)LLVM運(yùn)行Python。你可以用一個(gè)裝飾器指定你要用Numba編譯的函數(shù),Numba繼承Numpy來(lái)加速函數(shù)的執(zhí)行,Numba不做適時(shí)編譯,它的代碼是預(yù)先編譯的。
5、PyPy
在選擇CPython的簡(jiǎn)易替代語(yǔ)言時(shí),pypy無(wú)疑時(shí)優(yōu)異之選,與現(xiàn)有Python代碼保持高度兼容性,pypy也是默認(rèn)程序運(yùn)行時(shí)的一個(gè)很好選擇。PyPy使用了Just-in-Time即時(shí)編譯器,動(dòng)態(tài)編譯器與靜態(tài)編譯器不同,利用程序運(yùn)行的過(guò)程的數(shù)據(jù)進(jìn)行優(yōu)化。
PyPy使用適時(shí)編譯來(lái)加速Python,這項(xiàng)技術(shù)Google也在使用,Google在V8引擎中使用它加速Javascript。最近的版本PyPy2.5增加了一些提升性能的特性,其中有一項(xiàng)很受歡迎,它集成了Numpy,Numpy之前也一直被用來(lái)加速Python的運(yùn)行。
延伸閱讀1:Python優(yōu)勢(shì)
Python最大的優(yōu)勢(shì)在于效率。有時(shí)候程序員或科研工作者的效率比機(jī)器的效率更重要,對(duì)于很多復(fù)雜性的功能,使用更加清晰的語(yǔ)言能給程序減少更多的負(fù)擔(dān),從而大大增強(qiáng)程序的質(zhì)量,其易學(xué)性和擴(kuò)展性也能讓新手很快上手。雖然Python底層運(yùn)行速度要比C語(yǔ)言慢,但Python清晰的結(jié)構(gòu)能解放程序員的時(shí)間,同時(shí)很方便的和其他編程語(yǔ)言代碼(如C語(yǔ)言)融合在一起。