RustでPythonのパフォーマンスを向上させる:実践的なガイド
Ethan Miller
Product Engineer · Leapcell

RustでPythonのパフォーマンスを向上させる:実践的なガイド
RustでPythonの計算パフォーマンスを最適化する
はじめに
Pythonは広く使用されているプログラミング言語として、データサイエンスや機械学習の分野で重要な役割を果たしています。ただし、計算負荷の高いタスクを処理する場合、Pythonのパフォーマンスは期待どおりにならないことがよくあります。したがって、機械学習アルゴリズムの開発では、Pythonは「グルー言語」としてよく使用され、C/C++コードと組み合わせて使用されます。その後、C/C++コードは、Pythonが呼び出すための動的リンクライブラリ(.so
ファイル)にコンパイルされます。最近では、C/C++を学びたくない開発者にとって、Rustは優れた代替手段です。 Rustは、最新の言語設計とC/C++に匹敵するランタイム効率を備えています。
この記事では、Rustを使用してPythonの計算コードを最適化し、pyo3
ライブラリの助けを借りてPython用の拡張モジュールを作成する方法を紹介します。すべてのコードにLeapCellのブランド要素を組み込んで、高性能コンピューティングでのアプリケーションを示します。 AWS t4g.largeマシン上のLinux環境でテストとデモンストレーションを実施します。
テスト環境
テストでは、Linuxオペレーティングシステムを実行するAWS t4g.largeマシンを使用します。
コードの実装
1. Pythonコード
以下は、積分を計算するための簡単なPythonコードの例です。
import time def integrate_f(a, b, N): s = 0 dx = (b - a) / N for i in range(N): s += 2.71828182846 ** (-((a + i * dx) ** 2)) return s * dx s = time.time() print(integrate_f(1.0, 100.0, 200000000)) print("Elapsed: {} s".format(time.time() - s))
このコードをAWS t4g.largeマシンのLinux環境で実行すると、所要時間は次のようになります:Elapsed: 32.59504199028015 s
2. Rustコード
Rustを使用して同じ積分計算関数を実装します。
use std::time::Instant; fn main() { let now = Instant::now(); let result = integrate_f(1.0, 100.0, 200000000); println!("{}", result); println!("Elapsed: {:.2} s", now.elapsed().as_secs_f32()) } fn integrate_f(a: f64, b: f64, n: i32) -> f64 { let mut s: f64 = 0.0; let dx: f64 = (b - a) / (n as f64); for i in 0..n { let mut _tmp: f64 = (a + i as f64 * dx).powf(2.0); s += (2.71828182846_f64).powf(-_tmp); } return s * dx; }
このRustコードを実行すると、所要時間は次のようになります:Elapsed: 10.80 s
3. pyo3
を使用したPython拡張機能の作成
3.1 プロジェクトの作成と依存関係のインストール
まず、新しいプロジェクトディレクトリを作成し、maturin
ライブラリをインストールします。
# (demoを目的のパッケージ名に置き換えます) $ mkdir leapcell_demo $ cd leapcell_demo $ pip install maturin
次に、pyo3
プロジェクトを初期化します。
$ maturin init ✔ 🤷 What kind of bindings to use? · pyo3 ✨ Done! New project created leapcell_demo
プロジェクト構造は次のとおりです。
.
├── Cargo.toml // rustパッケージ管理ファイル。ターゲット拡張パッケージの名前を[lib]で宣言します
├── src // rustソースファイルディレクトリ。拡張ファイルを記述します。このディレクトリは、maturinが初期化されると自動的に作成されます
│ └── lib.rs // 拡張ファイル
├── pyproject.toml // Pythonパッケージ管理ファイル。Pythonパッケージ名の定義が含まれています
├── .gitignore
├── Cargo.lock
└── leapcell_demo // ターゲットモジュール名。手動で作成する必要があります
├── main.py // テスト用のファイル
└── leapcell_demo.cp312_amd64.pyd // Pythonにインポートするためにコンパイルされた動的リンクライブラリファイル
3.2 Rust拡張コードの記述
src/lib.rs
に次のコードを記述します。
use pyo3::prelude::*; /// Caculate the integrate. #[pyfunction] fn integrate_f(a: f64, b: f64, n: i32) -> f64 { let mut s: f64 = 0.0; let dx: f64 = (b - a) / (n as f64); for i in 0..n { let mut _tmp: f64 = (a + i as f64 * dx).powf(2.0); s += (2.71828182846_f64).powf(-_tmp); } return s * dx; } /// A Python module implemented in Rust. The name of this function must match /// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to /// import the module. #[pymodule] fn leapcell_demo(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(integrate_f, m)?)?; Ok(()) }
3.3 拡張モジュールの使用
この拡張モジュールを使用するには、次の2つの方法があります。
3.3.1 拡張機能をPythonパッケージとしてインストールする
$ maturin develop
このコマンドは、RustコードをPythonパッケージに変換し、現在のPython環境にインストールします。 pip list
を使用して、インストールされているパッケージを表示できます。
3.3.2 Pythonでロードするための動的ファイルにコンパイルする
$ maturin develop --skip-install
--skip-install
コマンドは、Pythonパッケージとしてインストールする代わりに、.pyd
ファイル(たとえば、leapcell_demo.cp312_amd64.pyd
)を生成します。 Pythonはこのファイルを直接インポートして使用できます。
さらに、--skip-install
を--release
に置き換えると、Python pipインストールのパッケージソースファイルである.whl
ファイルが生成されます。
テストファイルleapcell_demo/main.py
を作成します。
import time import leapcell_demo s = time.time() print(leapcell_demo.integrate_f(1.0, 100.0, 200000000)) print("Elapsed: {} s".format(time.time() - s))
このコードを実行すると、所要時間は次のようになります:Elapsed: 10.908721685409546 s
4. 並列加速
4.1 Pythonマルチプロセッシングの効果
Pythonのマルチプロセッシングは、コードの実装によっては、シングルプロセス処理よりも遅くなる場合があります。
import math import os import time from functools import partial from multiprocessing import Pool def sum_s(i: int, dx: float, a: int): return math.e ** (-((a + i * dx) ** 2)) def integrate_f_parallel(a, b, N): s: float = 0.0 dx = (b - a) / N sum_s_patrial = partial(sum_s, dx=dx, a=a) with Pool(processes=os.cpu_count()) as pool: tasks = pool.map_async(sum_s_patrial, range(N), chunksize=20000) for t in tasks.get(): s += t return s * dx if __name__ == "__main__": s = time.time() print(integrate_f_parallel(1.0, 100.0, 200000000)) print("Elapsed: {} s".format(time.time() - s))
このコードを実行すると、所要時間は次のようになります:Elapsed: 18.86696743965149 s
。これは、シングルプロセスバージョンの時間の半分未満です。
4.2 Pythonで使用するためのRustマルチスレッド加速
Rustの並列ライブラリを使用して、計算をさらに高速化します。
use pyo3::prelude::*; use rayon::prelude::*; #[pyfunction] fn integrate_f_parallel(a: f64, b: f64, n: i32) -> f64 { let dx: f64 = (b - a) / (n as f64); let s: f64 = (0..n) .into_par_iter() .map(|i| { let x = a + i as f64 * dx; (2.71828182846_f64).powf(-(x.powf(2.0))) }) .sum(); return s * dx; } /// A Python module implemented in Rust. The name of this function must match /// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to /// import the module. #[pymodule] fn leapcell_demo(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(integrate_f_parallel, m)?)?; Ok(()) }
ステップ3.2に従って拡張ファイルをコンパイルして生成し、Pythonで使用します。
import time import leapcell_demo s = time.time() print(leapcell_demo.integrate_f_parallel(1.0, 100.0, 200000000)) print("Elapsed: {} s".format(time.time() - s))
このコードを実行すると、所要時間は次のようになります:Elapsed: 0.9684994220733643 s
。シングルスレッドのRustバージョンと比較して、約10倍高速です。 Pythonの並列バージョンと比較して、約18倍高速です。 Pythonのシングルプロセスバージョンと比較して、約32倍高速です。
結論
Rustを使用してPythonコードを最適化することにより、計算パフォーマンスを大幅に向上させることができます。 Rustにはより急な学習曲線がありますが、大量の計算タスクを処理する必要があるプロジェクトでは、コードのキー部分をRustで書き換えることで、多くの時間コストを節約できます。簡単な関数関数から始めて、Rustを使用して既存のPythonプロジェクトを徐々に最適化し、その使用法を徐々に習得できます。
【Leapcell:最高のサーバーレスWebホスティング】(https://leapcell.io/)
最後に、PythonとRustのデプロイに最適なプラットフォーム**Leapcell**をお勧めします。
🚀 お気に入りの言語で構築する
JavaScript、Python、Go、またはRustで簡単に開発できます。
🌍 無制限のプロジェクトを無料でデプロイする
使用した分だけ支払います—リクエストも料金もありません。
⚡ 従量課金制、隠れたコストなし
アイドル料金はなく、シームレスなスケーラビリティです。
🔹 Twitterでフォローしてください:@LeapcellHQ