Rust で Python の拡張ライブラリ作成 と numpy との性能比較
この記事は Python Advent Calendar 5日目の記事です。遅れてすみません。
目次
Rust で Python の拡張ライブラリを書く
なぜRustなのか
この当たりを書いていると時間が無くなりそうなので、割愛したい。ただ、C++に馴染みのあるユーザーで高速に動作するコードを手っ取り早く書いていくにはRustが良さそうであるというのが自分なりの理解。特に、パッケージマネジャー当たりの優秀さはC++にはなくとても助かりそうである。メモリマネジメントもC++よりストレスレス。
PythonのAdventでRustなの?
Pythonのヘビーユースしだすと、C/C++ Extention を書いたり、Cythonなどを使って高速化していくことは特別なことではなくなる。そのひとつの選択肢として、これからはRustが良さそうだということで、勉強を兼ねて今回の記事を書くことにした。私自身はRustの初心者なので、間違っているところ等があればぜひご指摘いただきたい。
Rustのインストール
1 2 |
# install Rust curl https://sh.rustup.rs -sSf | sh |
Linux / MacOS ユーザーには上記コマンドで一発でインストールできる。Windowsユーザーはインストーラーを使ってインストールするが、RustはWindowsでは結構難があるので、その当たりは注意してほしい。
Rust コンパイル用 setuptools-rust をインストール
1 |
pip install setuptools-rust |
Rustをpythonのsetuptoolsを使ってコンパイルできるライブラリ。python setup.py を使って、rustのライブラリを作成できるようになる。
Python Rust Extention
どうやら2本ある様子。他の記事ではだいたい、rust-cpython
を紹介しているのが多い。
rust-cpython
PyO3
比較
rust-cpython custom class
- rust-cpython uses whole new language based on macros
- it is very hard to extend py_class! macros, for example async/await support.
- generated functions are used for access to struct attributes.
- To drop PyObject GIL is required.
pyo3 custom class
- use proc_macro and specialization for class implementation (nightly is required)
- pyo3 does not modify rust struct. it is possible to define needed traits and make rust type compatible with python class without using #[py::class] macro.
- class customization is based on specialization and traits and associated types. separate trait is defined for each type
- of customization (i.e. PyMappingProtocol, PyNumberProtocol). macro is used for simplicity, but it is possible to make rust type compatible with specific customization without using proc macros.
- pyo3 does not inc ref for borrowed ptrs, PyObject does not need GIL to drop.
- pyo3 at least 15% faster.
pyo3 のが速い(イケてる)と書いているので、 pyo3 を使っていきたかったが、rust-numpyがrust-cpythonにしか対応していないので、rust-cpythonを使う。githubスターはrust-cpthonのほうが多い。setuptools-rustはPyO3の開発チームによるもので、READMEではpyo3のみが紹介されている。
プロジェクト作成
1 2 3 |
mkdir rust_binding_4_python cd rust_binding_4_python cargo new pyext-example |
どうやら、rust-cpythonは2.7では現状動かない様子。Python3 に環境を変更する。
1 |
pyenv local miniconda3-4.1.11 |
Cargo.toml
1 2 3 4 5 6 7 8 9 10 11 12 |
[package] name = "pyext-example" version = "0.1.0" authors = ["fx_kirin"] [dependencies] numpy = { git = "https://github.com/termoshtt/rust-numpy" } cpython = "0.1" ndarray = "0.10" [lib] crate-type = ["cdylib"] |
Rustのライブラリの作成を行うので、必要dependenciesをセットしてください。rust-numpy
はgithubから直接取得しておかないとちゃんと動かなかった。
lib.rc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#[macro_use] extern crate cpython; extern crate numpy; extern crate ndarray; use numpy::*; use ndarray::*; use cpython::{PyResult, Python, PyObject}; /* Pure rust-ndarray functions */ // immutable example fn sum(x: ArrayViewD<f64>) -> f64 { x.scalar_sum() } // wrapper of `sum` fn sum_py(py: Python, x: PyArray) -> PyResult<f64> { let x = x.as_array().into_pyresult(py, "x must be f64 array")?; let result = sum(x); Ok(result) // Python function must returns } /* Define module "rust_binding" */ py_module_initializer!(rust_binding, init_rust_binding, PyInit_rust_binding, |py, m| { m.add(py, "__doc__", "Rust extension for NumPy")?; m.add(py, "sum", py_fn!(py, sum_py(x: PyArray)))?; Ok(()) }); |
rust-numpy
はrust-ndarray
に変換してくれるので、sum functionを呼んでみました。rustの拡張は引数とか返り値の設定とかを都度読み込みの設定をしなくていいので楽ですね。
setup.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#! /usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup from setuptools_rust import Binding, RustExtension setup(name='pyext', version='0.1.0.0', rust_extensions=[ RustExtension('pyext.rust_binding', 'pyext-example/Cargo.toml', binding=Binding.RustCPython)], packages=['pyext'], # rust extensions are not zip safe, just like C-extensions. zip_safe=False) |
Build python package
1 |
python setup.py develop |
性能比較
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ python main.py ## benchmarker: release 4.0.1 (for python) ## python version: 3.5.2 ## python compiler: GCC 4.4.7 20120313 (Red Hat 4.4.7-1) ## python platform: Linux-4.4.0-101-generic-x86_64-with-debian-stretch-sid ## python executable: /home/zenbook/.pyenv/versions/miniconda3-4.1.11/bin/python ## cpu model: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz # 3924.609 MHz ## parameters: loop=100000, cycle=1, extra=0 ## real (total = user + sys) numpy.sum 0.2475 0.2500 0.2500 0.0000 faster_numpy.clibrary.sum 0.1182 0.1200 0.1200 0.0000 rust_binding.sum 1.7960 1.7800 1.7800 0.0000 ## Ranking real faster_numpy.clibrary.sum 0.1182 (100.0) ******************** numpy.sum 0.2475 ( 47.7) ********** rust_binding.sum 1.7960 ( 6.6) * ## Matrix real [01] [02] [03] [01] faster_numpy.clibrary.sum 0.1182 100.0 209.5 1519.9 [02] numpy.sum 0.2475 47.7 100.0 725.5 [03] rust_binding.sum 1.7960 6.6 13.8 100.0 |
結構頑張ったけど、結局自作のnumpy用高速計算パッケージが一番早くて、numpyの標準ライブラリにも及ばない感じ。軽く調べたところ、rust-numpy
のデータ変換だけで0.6秒かかっているので、速度で勝負するのは根本的に厳しそう。高速化できるのかな。
Github Repo
参考記事



About Fx-Kirin
2009年10月にFXを開始、翌年2010年5月から脱サラをしてFX業界に専念。 2012年10月頃から本格的に勝ち始め、一月で資産を倍にする、2年半月間負けなし等、安定した収支で2013年11月に生涯FX収支が1億を超える。 投資スタイルはシステムトレード。プログラミングの知識がほぼない状態から、独学で自分がしたいと思うことであればほぼ実現することが可能なレベルまで成長。好きな言語はRuby, Python。必要となればC++からVBA、Pascal等なんでも行う。MT4/MT5のプログラミングも得意。 2011年にはFXで稼いだ資金をもとにシンガポールに移住し、留学も兼ねて起業をチャレンジするほど、ビジネスを興すことに熱意がある。国内の業者を主に使い始めたことから、2012年に帰国。零細株式会社経営中。
- Web |
- More Posts (410)
Adsense
関連記事
-
-
Flast-Sockets + redis-py で簡単 Websocket サーバー実装
参考にしたサイト Using WebSockets on Heroku with Python | Heroku
-
-
swig で foofunction is private と怒られた時。
例えばのエラーとしてはこれ。 問題は、公開する予定のクラスのpublicインスタンス変数にprivateにしなけれ
-
-
Windowsユーザ御用達の uci.edu から直接python wheelをインストールしてくれるライブラリ pipwin
あんまり情報が出てこないのでメモ書き。 https://twitter.com/fx_kirin/status/9
-
-
stop automatically closeing vim-ipython output with jedi-vim
Even though I commented out the following code in vim_ipytho
-
-
重回帰分析による米雇用統計の予測モデルを作成してみる
この記事はPython その2 Advent Calendar 2015 の17日目の記事です。 1 はじめに
-
-
PythonのThreadを待機させるか、必要の度に作成するのかのベンチマーク比較
QueueとThreadのベンチマーク比較 2つのケースについて比較検証してみました。 実際に処理する内
-
-
SQLAlchemy のマイグレーションライブラリ Alembic を使ってみる。
SQLAlchemyの作者が作ったデータベースマイグレーションツール。個人的には、SQLAlchemyは使わないが、
-
-
Python2 から Python3 へのC Extension の移行
最初に追加 モジュールの初期化と状態情報を書き換える initmyextension 関数などの初期状態の関
-
-
Python Pandas からお手軽に highcharts が使える kanichart 作りました。
Kanichart fx-kirin/kanichart: Easy(簡易) plotting library.
Adsense
NEW ENTRY
-
- Linux Mint 20 での日本語の設定について。
フォントの設定とかはいろいろなところで触れられているので、他にない情報だけ。 TL;DR F
-
- joblib によって謎のバグが起こる
joblib 0.14.1 にて確認.0.13.2 だと起こらない.import joblib を消
-
- Fixing kernel error AMD-Vi: Event logged IO_PAGE_FAULT on Ryzen Machine
My pc was periodically shut down on 7:40 am JS
-
- Ubuntu で仮想ディスプレイを使う
雑多な備忘録ですが、せっかくなので残しておきます。 Ubuntu 18.04 の resolv.c
-
- PYPIへの登録を10秒でできるようになる方法
pip 使ってますよね Pythonを使っている人であれば、pip installでライブラリ
Twitter
RSS
カテゴリー
-
人気記事一覧