2024年2月14日
本記事は3重for文での比較を主題にしていましたが、
おそらくRustでの結果を想定通りに得られていないと考えられます。
参考にしていただいた方は、申し訳ありません。
ひとつ学びとして記事は残します。コメントありがとうございました。
2023年9月21日
いただいたコメントに基づき、現在、実験結果の正しさについて確認中です。
これにより今後の編集で結果が変わる可能性があります。
RustとPythonとの3重for文の処理時間を比較してみた
最近、仮想通貨取引所から個人で収集し続けたデータが約1億点になり、
Pythonでは一括での処理が現実的ではなくなってしまいました。
特にfor文を含む処理がネックになっていると思っていて、
numpyやnumbaで何とか置き換えてきたものの、
可読性なども考慮すると限界を感じています。
やむを得ず言語レベルでの変更を検討していたところ、
Rustは書きやすそうで速そうだということで、
一旦Rustの速さを体感したく検証してみました。
(自由にfor文を書きたい...!)
実行環境
Windows11, VSCode
CPU: 11th Gen Intel(R) Core(TM) i7-11800H(論理プロセッサ数: 16)
バージョン | |
---|---|
Rust | 1.68.0 |
Python | 3.10.5 |
numba | 0.56.0 |
実装
n
を引数にとり、3重ループの処理を行う関数f
を言語ごとに用意し、n
を変えながらそれぞれの処理時間を計測します。
Rust
fn f(n: i64) -> i128 {
let mut count = 0;
for i in 0..n {
for j in 0..i {
for _ in 0..j {
count += 1;
}
}
}
count
}
Python
def f(n):
count = 0
for i in range(n):
for j in range(i):
for _ in range(j):
count += 1
return count
Python + numba
from numba import njit
@njit
def f(n):
count = 0
for i in range(n):
for j in range(i):
for _ in range(j):
count += 1
return count
Python + numba(prange)
すぐにCPU使用率が100%に達します。
from numba import njit, prange
@njit(parallel=True)
def f(n):
count = 0
for i in prange(n):
for j in prange(i):
for _ in prange(j):
count += 1
return count
結果
上記の3重ループでRustとPythonとの処理速度の比較を行った場合、
RustはPythonと比べて桁違いに速いということが分かりました。
同じ時間で計算可能なn
の範囲が広がるので、データサイズが大きい場合などに有用だと考えられました。
(rayonなどのクレートを使えばより高速化できる可能性もあります)
Pythonにnumbaを導入した場合でも、Python標準に比べてかなり速くなりますが、
Rustはさらに速かったです。
ただし、Rustをdebugモードでコンパイルした場合の処理時間は速いとは言えず、
簡単な動作確認以外では--release
オプションをつけてコンパイルしたほうが良さそうです。
n | 処理時間(秒) | |
---|---|---|
Rust(debugモード) | 1,000,000 | 258 |
Rust | 10,000,000,000 | 11 |
Rust | 100,000,000,000 | (1分を超えたため中断) |
Python | 1000 | 3.8 |
Python | 10000 | (1分を超えたため中断) |
Python + numba | 1000 | 0.2 |
Python + numba | 1,000,000 | 12.2 |
Python + numba | 10,000,000 | (1分を超えたため中断) |
Python + numba(prange) | 1,000,000 | 5.6 |
Python + numba(prange) | 10,000,000 | (1分を超えたため中断) |
感想
Rustの速さを実感したいのが主だったため、そもそもPythonに不利な処理を実装している点ご理解いただきたいです。(Python大好き!)
とはいえ、想像以上に速すぎて少し笑ってしまいました。
ちなみに、Rustでのf(10_000_000_000)
の結果は166666666616666666670000000000
でした。