https://josephok.github.io/2019/03/30/Speed-up-Python-program-with-Rust/
Python
具有開發快速的特點,但是在運行效率上比靜態編譯型語言慢不少,我們今天要介紹的Rust
就是其中一種。
Rust是一種安全、並發、實用的編程語言,有着驚人的運行速度,能夠防止段錯誤,並保證線程安全,使每個人都能夠構建可靠、高效的軟件。
當我們的Python
程序出現性能瓶頸時,可以從如下幾個方面優化:
- 優化算法,使用更高效率的算法來提升性能;
- 使用並發,如多線程程序;
- 使用編譯型語言編寫擴展;
- 優化網絡、磁盤、數據庫等。
性能優化是個大命題,我們需要從多個方面着手考慮,今天我介紹的是第3種方法,並且選擇Rust
語言。我們將編寫一個so
擴展供Python
端調用。
這里不會講Rust
的入門,具體規范可以看官方文檔或者中文文檔:https://rustlang-cn.org/
我們選擇Httpbin作為基准程序,進行修改然后對比效果。
1. 原始代碼
為了簡單,我稍微修改了view_get
,使之只返回客戶端的請求方法。如下:
1 |
{ |
代碼如下:
1 |
# httpbin/core.py |
2. 測試一下原始代碼性能:
使用wrk進行benchmark測試:
1 |
wrk http://127.0.0.1:5000/get -c 400 -t 10 |
可以看出:平均時延為315ms左右,RPS為434左右。
3. 使用rust-cpython編寫擴展
首先新建一個lib
類型的項目,比如名字為handle
:
1 |
cargo new handle --lib |
這樣就在當前項目下新建了一個目錄:handle
,我們需要編輯handle/Cargo.toml
:
1 |
[package] |
然后是編輯handle/src/lib.rs
:
1 |
|
這里的handle
是模塊名,ret_py_dict
就是模塊的方法,供Python
調用,使用方法:
1 |
import handle |
然后需要編譯此模塊,我們使用Makefile
編寫編譯規則:
1 |
build: |
執行make
命令編譯並將so
文件拷貝到指定目錄。
4. Python
端調用方法
編寫一個view_get1
方法:
1 |
from . import handle |
與我們的原始函數唯一區別是:jsonify
函數的參數,即響應內容是由擴展模塊產生,類型都是dict
。
curl
響應為:
1 |
curl localhost:5000/get1 |
結果一致。
5. 測試使用了擴展的性能
1 |
wrk http://127.0.0.1:5000/get1 -c 400 -t 10 |
可以看出:平均時延為248ms左右,RPS為544左右。
比原始版本:時延低70ms,RPS高110,效果比較明顯,這里僅僅改寫了獲取對象屬性的方式。
6. 總結
如果想繼續優化,可以考慮改寫jsonify
函數。在這里我們提出了一個優化Python
程序性能(Latency, RPS)的方案。前文也說到過,優化性能應該先從代碼結構、算法方面做優化,當語言成為瓶頸時,使用Rust
編寫擴展實為一種好的方式。
參考:
https://developers.redhat.com/blog/2017/11/16/speed-python-using-rust/