python的性能優化方案
python的GIL,多線程,多進程
- GIL: Global Interpreter Lock(全局解釋器鎖),每個CPU在同一時間之內只能執行一個線程,因爲單核CPU的多線程其實都只是併發不是並行。
- 單CPU中進程只能是併發,多CPU進程可以並行
- 單CPU單核中線程只能併發,單CPU多核中線程可以並行
- 並行: 多事件在同一時刻發生
- 併發: 多事件在同一時間間隔內發生
- 每個線程的執行方式: 獲取GIL --> 執行代碼 --> 釋放GIL,在一個python進程裏面,只有一個GIL,如果線程拿不到這個GIL就無法運行。
- GIL的釋放邏輯: 1. python2:當前線程遇見IO操作或者ticks計數達到100。2. python3:改用計時器,執行時間達到閥值釋放GIL
使用Ubuntu Apache AB進行壓力測試
sudo apt-get install apache2-utils
ab -n 100 -c 10 http://localhost/demo/
-n 代表的是總的請求數,-c代表一次併發裏面的請求數
具體項目優化方案:
-
read DB:讀取數據庫的時候,使用cache
-
代碼邏輯:儘量避免在for循環裏面使用query
-
給logger加上判斷,當debug模式爲False的時候,很多不必要的地方不需要寫log
-
gunicorn:使用gevent啓用worker,將worker的數量變成三個,核數+1,將gevent放在requirement中。Worker個數,Worker類型,TImeout時間
-
Nginx: 修改配置文件,timeout設置爲600/300s
在最外面加上:worker_rlimit_nofile 65535;
在http塊內加上:
fastcgi_send_timeout 600; fastcgi_read_timeout 600;
在server塊的location裏面加上:
proxy_connect_timeout 600s; proxy_read_timeout 600s; proxy_send_timeout 600s;
-
NAS:掛載參數上需要增加一個noresvport參數來規避以後例行維護可能造成的NAS服務中斷https://c.tb.cn/a.cAQOl
-
使用python的一些計算運行時間的工具來優化代碼,CProfile、line_profiler、TimeDelta
-
對python本身的一些優化 pypy/cpython
使用line_profiler工具分析python代碼性能以及性能調優
line_profiler
是一個對函數進行逐行分析的模塊,kernprof
是一個可以運行line_profiler
或者python標準庫cProfile
的一個很方便的腳本工具。
安裝:
$ pip install line_profiler
遇到錯誤提示沒有Cpython,安裝一下:
pip install Cpython
繼續報錯:command 'x86_64-linux-gnu-gcc' failed with exit status 1
解決方案:https://github.com/scrapy/scrapy/issues/2115
裏面的sudo apt install python3.6-dev
解決了問題
首先使用kernprof腳本運行來開始我們的性能優化工作:
kernprof -l run.py
上面的操作會創建一個LineProfiler
的實例並且會把它插入到命名空間裏面。然後它能以裝飾器的方式來使用,所以我們只需要把我們需要分析的函數上面套上這個裝飾器:
@profile
def func_need_profile(*args, **kwargs):
...
這裏直接加上裝飾器,不需要在代碼裏面額外import任何東西。
kernprof
會把分析的結果放在script_to_profile.py.lprof
這個二進制文件裏面,然後我們可以去看這個分析結果:
python -m line_profiler run.py.lprof