Python 程式碼精簡和優化
- 2020 年 1 月 6 日
- 筆記
Python很簡單,容易使用,開發效率很高,移植性很好,程式碼資源也很豐富,被廣泛使用。但是Python程式碼編出來的動態庫比較大,python庫很全,缺點就是庫比較大。
在記憶體佔用方法,隨著py庫的引入,記憶體也成倍的增加,這裡來討論下如何來給Python瘦身,以及如何優化記憶體的佔用。
一、如何給Python的動態庫瘦身。
Python的程式碼還是很精練的,所以要減小小程式碼的大小比較困難,但是仍然有一些思路來減小Python庫的大小。
1、strip python動態庫。
動態庫一般都是包含符號表,這些在調用的時候很有用,但是對於release版本,完全可以把符號表去調,方法就是用strip命令,這樣大小可以從八九兆銳減到3兆以內。
2、使用程式碼優化選項:-O3,該參數會對程式碼進行最大程度的優化,包括優化生成的二進位程式碼的大小,缺點是優化後會對調試帶來困難。
3、去除程式碼中的Doc String.
Python的程式碼里有用PyDoc_STRVAR宏定義的模組的幫助說明,這些是可以去掉的,方法是在configure的時候指定–without-doc-strings,這樣生成的pyconfig.h中就會不會有下面的定義:
#define WITH_DOC_STRINGS 1
這可以減小生成的動態庫的大小,當然在運行時也可以減小模組的記憶體的佔用,因為這些模組不再包含幫助資訊。
4、去掉unicode支援。
python中unicode支援不是必需的,當然python 3另當別論。python中要支援unicode可以採用utf-8編碼的方式。去掉unicode的支援可以在configure的時候使用下面的參數:
–enable-unicode=no
這樣,在pyconfig.h中會去掉下面的定義:
#define Py_USING_UNICODE 1
二:如何減小Python的擴展庫的大小?
Python的擴展庫放在lib目錄下,可以在lib目錄下執行下面的命令來編譯Python程式碼:
python -OO -m compileall .
這樣會生成pyo擴展名的庫文件,-OO參數會去掉doc string,這樣在py文件中注釋比較多的時候可以顯著減小編譯目標文件的大小。
注意不要使用絕對路徑:
如python -OO -m compileall /path/to/python/lib 這樣使用絕對路徑的命令,因為生成pyo文件的時候,,每個函數和類的方法會生成一個一個的code object對象,每個code object都會保存它所在的模組的路徑,如果使用絕對路徑,在路徑比較長的時候,函數又比較多的時候,很顯著的增加pyo文件的大小。
當然,在程式碼運行時,也可以減小記憶體的佔用量。
三、如何裁減擴展庫。
有個py2exe的工具可以打包python程式碼和依賴的動態庫,把python所必須的擴展庫打包到zip文件中,但是實際上這個zip包往往並不是最精簡的。其實裁減的最大難點是要找出所有依賴的模組,可以用下面的方法來找出某個模組所依賴的其它模組:
import importlib def module_diff(mod): import sys keys = [] for key in sys.modules.keys(): keys.append(key) importlib.import_module(mod) for key in sys.modules.keys(): if not key in keys: print key,sys.modules[key]
如要查看multiprocessing模組所依賴的模組,可以用下面的命令:
module_diff('multiprocessing')
將會得到下面的輸出:
multiprocessing.atexit None multiprocessing.weakref None multiprocessing.signal None threading <module 'threading' from 'C:Python27libthreading.pyc'> cPickle <module 'cPickle' (built-in)> _multiprocessing <module '_multiprocessing' from 'C:Python27DLLs_multiprocessing.pyd'> multiprocessing.os None multiprocessing.itertools None multiprocessing.threading None multiprocessing.util <module 'multiprocessing.util' from 'C:Python27libmultiprocessingutil.pyc'> multiprocessing.sys None cStringIO <module 'cStringIO' (built-in)> multiprocessing._multiprocessing None multiprocessing.multiprocessing None thread <module 'thread' (built-in)> atexit <module 'atexit' from 'C:Python27libatexit.pyc'> multiprocessing <module 'multiprocessing' from 'C:Python27libmultiprocessing__init__.pyc'> weakref <module 'weakref' from 'C:Python27libweakref.pyc'> itertools <module 'itertools' (built-in)> time <module 'time' (built-in)> multiprocessing.process <module 'multiprocessing.process' from 'C:Python27libmultiprocessingprocess.pyc'
這樣就可以知道所依賴的模組了。
要查看所有的模組,則更簡單:
def print_all_module(): import sys keys = [] for key in sys.modules.keys(): print key,sys.modules[key]
在程式碼初始化完後執行上面的函數,就可以知道程式運行所需的模組了。