LoginSignup
1
0

【Rust】Python(+numba)との3重for文の速度比較...をしたかった

Last updated at Posted at 2023-04-18

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

main.rs
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

main.py
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

main.py
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%に達します。

main.py
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でした。

1
0
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0