3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PyCon JP 2024で「Python x Rust」をテーマに登壇しました(ベンチマークの追加検証あり)

Posted at

株式会社RevCommでエンジニアをしている skokado(@_skokado)といいます。

2024年10月27日から28日にかけて行われたPyCon JP 2024で登壇してきました。

https://2024.pycon.jp/ja

PNG_yoko.png

発表内容

タイトルは『Rustを活用したPythonライブラリの開発』でした。
https://2024.pycon.jp/ja/talk/7GPRYL

発表資料:

多くの方にお越し頂きありがとうございました。

image.png

Rust (PyO3) ベンチマークの追加検証

発表後、質疑応答の時間で多くの質問を頂きました。
特に途中に説明したベンチマーク比較について、詳しい方から質問を頂いたり発表後詳しくお話しすることができ、私自身かなり勉強させて頂けました。

少し追加検証してみたので、それについて記します。

Cython と Rust (PyO3) の性能比較について

「ベンチマーク結果は Python < Rust < Cython」と話しました。
特に "Rust < Cython" の要因として「Cython と PyO3 の成熟度の違い」と説明しました。

後から検証した結果、これはベンチマークに用いたサンプルコードに対してCythonが特に最適化されている可能性が高いことが分かりました。
最適化も "成熟度" の一つに含まれるかもしれませんが、補足しておきます。

対象のベンチマークはこちらの「L2ノルムを計算する関数」です(Link

Rustを活用したPythonライブラリの開発 (PyCon JP 2024).png

Cython (GIL なし)の関数を追加検証したところ、以下の実行結果を得ました。

n (配列長) 所要時間 (sec)
1000 0.023
10000 0.0029
100000 0.0148
1000000 0.0009
10000000 0.0036
追加検証スクリプト
import random
import timeit

import numpy as np

import cymodule


def init_array(length: int) -> np.ndarray:
    return np.array([
        round(random.random() * 100, 2)
        for _ in range(length)
    ])


repeat = 4

print("n,duration")
for exp in range(3, 7 + 1):
    n = pow(10, exp)
    arr = init_array(n)

    dur = timeit.timeit(lambda: cymodule.l2norm(arr), number=repeat)
    dur = round(dur / repeat, 4)
    print(f"{n},{dur}")

つまり所要時間が配列長に依らずほぼ O(1) であり、何らかの最適化が働いている可能性が高いです(SIMDが関係している? とか?)

なお、ビルドのオプションには -O3 が含まれていました。
https://clang.llvm.org/docs/CommandGuide/clang.html#cmdoption-O0

$ cd c_api_cython
$ pip3 install . -v
...
  building 'cymodule' extension
  clang -pthread -fno-strict-overflow -Wsign-compare -Wunreachable-code -DNDEBUG -g -O3 -Wall -fPIC -fPIC -I/path/to/.venv/include -I/path/to/python/3.12/include/python3.12 -c cymodule.c -o build/temp.linux-x86_64-cpython-312/cymodule.o -fopenmp

また筆者の検証環境ツールのバージョンは以下の通りでした。

  • Python: 3.12.6
  • clang: 18.1.3
  • OpenMP (libomp-dev): 1.18.0
  • Cython: 3.0.11

今の私ではこれ以上詳しく調査できなさそうなので、追加検証としてはここまでに留めておきます(詳しい方いたらぜひ教えてください🙏)。

追加ベンチマーク (素数計算)

ベクトル演算における最適化の性能影響を無くすため、素数を計算するアルゴリズムをベンチマーク例にした追加検証を実施してみました。

  • エラトステネスの篩
  • 愚直方式

それぞれ Python で実装したコードは以下です。

def eratosthenes(limit: int) -> list[int]:
    prime_flags: list[bool] = [True for _ in range(limit + 1)]
    p = 2
    while p ** 2 <= limit:
        if prime_flags[p]:
            for i in range(p ** 2, limit + 1, p):
                prime_flags[i] = False
        p += 1
    primes: list[int] = [p for p in range(2, limit) if prime_flags[p]]
    return primes


def get_primes(max: int) -> list[int]:
    # n以下の素数一覧を返す愚直な実装
    primes = [2]

    for n in range(3, max + 1, 2):
        i = 3
        while i * i <= n:
            if n % i == 0:
                break
            i += 2
        else:
            primes.append(n)

    return primes

上記と同様のアルゴリズムをCython, Rustでも実装してベンチマークを計測しました。
他のコードはGitHubをご覧ください。
https://github.com/skokado/speak/tree/v2024.10.01/pycon-jp-2024/sample-codes/benchmarks

  • エラトステネスの篩

※所要時間は (sec)

limit Python Cython Rust (PyO3)
1000 0.0 0.0 0.0
10000 0.0 0.0 0.0
100000 0.01 0.0 0.0
1000000 0.09 0.05 0.01
10000000 1.06 0.62 0.05
100000000 12.29 7.61 0.96

PyO3 < Cython < Python

  • 愚直方式

Cython ≒ PyO3 < Python

max Python Cython Rust (PyO3)
1000 0.0 0.0 0.0
10000 0.0 0.0 0.0
100000 0.06 0.01 0.01
1000000 1.93 0.15 0.16
10000000 55.5 4.14 4.18

上記の例なら総じて Rust (PyO3) が高速であることが分かりました!🦀

終わりに

嬉しいことに昨年のPyCon APAC 2023に引き続きの登壇でした
PyCon APAC 2023に参加&登壇してきました

発表の中でベンチマークに触れたことで多くの質問、コメントを頂けて私自身の勉強につながりました。

スポンサー、参加者、運営スタッフの皆さん、そして会場で話してくださった方々に改めて感謝申し上げます。

終わりに (2)

今月の PyCon APAC 2024 でも登壇してきます!🦀

image.png

3
1
0

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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?