22
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PythonからRustを呼んで高速化! PyO3 チュートリアル:簡単な関数をラップする その➀

Last updated at Posted at 2020-04-02

概要

1. Pyhtonでアルゴリズムまで書いてあるのは速度面では好ましくないな〜
2. よし、C, C++あたりで書いてあるものを探して、それをPythonから呼んで高速化しよう。
3. なかなかいいライブラリ見つからんな、
4. おっ、Rustていう言語で書かれてるのならあったぞ
5. RustてPythonから呼べんのか??

最終的な目標

というわけで、今までC++のライブラリをPythonから呼んで高速化を図るための「Cython」チュートリアルを書いてきましたが、

今回からはRustをPythonから呼んで高速化するための「PyO3」というライブラリのチュートリアルを書いていきます。

最終的な目標は、
Rustで書いた関数やクラス(的なもの?)をPythonから気軽に呼べるようになること
です。

このPyO3(gitはここ)は、開発の真っ只中であり、バージョン更新が(おそらく)凄まじい速度で行われております。

今回の目標

そもそもRust初見の状態からスタートして、
PythonからRustで書いた関数を呼べるようになる、という目標のもとPyO3を触ってみました。

キータにも、他ブログでもいくつかの解説記事が出ております。

今回は、
RustモジュールをPythonから実行する (PyO3)
さんのコードをお借りして、それにsetup.pyを付け加えて、Rustで書かれた関数をPythonから呼んでみたいと思います。

手順

rustのインストール

1行目を実行するとインストールについて3択で聞かれますがdefaultインストールの1を選んで問題ないかと思います。

curl https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env

rust nightlyのインストール

PyO3を使用するために必要になります。
開発中のクレートをたくさん含んだβバージョンと言うようなものでしょうか。

バージョンを確認してみる
このバージョンを今回は使います。

$rustc --version
rustc 1.44.0-nightly (f509b26a7 2020-03-18)
$ rustup --version
rustup 1.21.1 (7832b2ebe 2019-12-20)
rustup install nightly
rustup default nightly

rust のプロジェクトを作る

--lib をつけることで、ライブラリ用のプロジェクトを作ります。
今回は、プロジェクト名をexampleとしました。

cargo new --lib example

$ tree example/
├── Cargo.toml
├── setup.py
├── src
│   └── lib.rs

フォルダ構造はこのようになっています。

Cargo.tomlを設定する

RustがC++などより優れていると言われていることのひとつ、ライブラリの管理の手軽さがここにあります。
Cargo.tomlに必要なライブラリを書くのですが、CMakeLists.txtとかよりはるかに簡単で見やすいです。

Cargo.toml
[package]
name = "test"
version = "0.1.0"
edition = "2018"

[lib]
name = "test_library"
crate-type = ["cdylib"]

[dependencies.pyo3]
version = "0.9.1"
features = ["extension-module"]

今回はpyo3をライブラリとして使用し、
作る目的のライブラリは、test_libraryです。

すなわち、Pythonで

test.py
import test_library

みたいに書きたいわけです。

Rustで関数を作る

とりあえず写経してみる

コードはRustモジュールをPythonから実行する (PyO3)
さんのものを丸々持ってきました。
エラトステネスのふるいの実装だそうです。


//lib.rs

use pyo3::prelude::*;


// This is the test function in Rust, getting prime number, which is called by python as get_prime_numbers
#[pyfunction]
fn get_prime_numbers(n: i32) -> PyResult<Vec<i32>> {
    let mut flags = Vec::new();
    for _ in 0..n+1 {
        flags.push(true);
    }

    let upper = (n as f32).sqrt().floor() as i32;
    for i in 2..upper+1 {
        if !flags[i as usize] {
            continue;
        }

        let prime = i;

        let mut j = prime * 2;
        while j <= n {
            flags[j as usize] = false;
            j += prime;
        }
    }

    let mut primes = Vec::new();
    for i in 2..n+1 {
        if flags[i as usize] {
            primes.push(i);
        }
    }

    Ok(primes)
}



Rustの構文を細かく解説できるだけの能力がありませんので、
この関数はあっているものとし、どうこれがPythonから呼べる形にラップされているかというところを解説します。

#[pyfunction]
fn get_prime_numbers(n: i32) -> PyResult<Vec<i32>>

をみてみると、
まず#[pyfunction]のデコレータ的なものがこの関数の引数もしくは返り値にPyO3によりパースされたPythonオブジェクトが入ることを宣言しています。

このget_prime_numbers関数はint32を引数に取り、それ以下の素数をリストとして返す関数です。
このとき、返り値のところが、PyResult<Vec<i32>>となっていますが、
このPyResultuse pyo3::prelude::*;から来ています。

また、Vec<i32>は、下の型の対応表のようになっており、PyResut によってPythonのList型に変換されます。

Rust Python
i32, usize int
f32, f64 float
bool bool
Vec<T> list
String str
HashMap dict

[[Rust] PyO3 で Python パッケージを作成]からの引用 (https://qiita.com/osanshouo/items/671888bdd6afeec1e939)

また、最後の

Ok(primes)

Veclistへと変換しています。

まとめ

ここで終わると参考文献をほとんどコピペしたものになって申し訳ないのですが、
一度ここで区切ります。

まとめとして、

  • Rustのインストールを行った。
  • Rustのライブラリ用のプロジェクトを作成した。
  • Cargo.tomlを書いた。
  • 関数を写経し、Rust->Pythonの型変換を確認した。

以上になります。

次はlib.rsを追記し、setup.pyも加え実際にライブラリのオブジェクトファイルとしてコンパイルしていきます。

今回はこの辺で。

おわり。

22
27
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
22
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?