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 3 |
# install Rust curl https://sh.rustup.rs -sSf | sh |
Linux / MacOS ユーザーには上記コマンドで一発でインストールできる。Windowsユーザーはインストーラーを使ってインストールするが、RustはWindowsでは結構難があるので、その当たりは注意してほしい。
Rust コンパイル用 setuptools-rust をインストール
1 2 |
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 4 |
mkdir rust_binding_4_python cd rust_binding_4_python cargo new pyext-example |
どうやら、rust-cpythonは2.7では現状動かない様子。Python3 に環境を変更する。
1 2 |
pyenv local miniconda3-4.1.11 |
Cargo.toml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[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 30 |
#[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 15 |
#! /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 2 |
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 24 25 |
$ 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 (383)
Adsense
関連記事
-
-
Python x64 & MinGW64 環境の構築
流石に詰まりまくったのでまとめることにする。 MSYS2 をインストール 個人的にこれからメインで使いたいと思っ
-
-
vim-ipythonをWindows 7 x64で使うとR6034 が出る件
個人的なただの忘備録。 Visual Studioのコマンドプロンプトから実行すること。 http://st
-
-
JAVA の SHA1 Digestの作り方
>>> import base64 >>> import hashlib >>> base64.b64encode(
-
-
まだ Python の datetime で消耗しているの? maya 使おうぜ
この記事は Python Advent Calendar 2016 の 24日目の記事です。 当初は SCOOP
-
-
ipdb だけではなく IPython.embed も使おう
ipdb だと複数行の挿入ができなかったりするが、その問題が解消される。明らかにこちらのほうが使い勝手がいい。行のデ
-
-
話題のクローラー・スクレイピング!PythonならScrapyが超優秀な件
Rubyの読書会に行ったら、Pythonの面白いお話を聞けたというお話です。 Rubyクローラー本の読書会に参
-
-
Pythonで簡単自動化!PyAutoGuiが便利すぎて感動したのでご紹介
以前こんな記事を書いていたのですが、これがまったく不要になるとても便利なPython Libraryがあった
-
-
PythonのThreadを待機させるか、必要の度に作成するのかのベンチマーク比較
QueueとThreadのベンチマーク比較 2つのケースについて比較検証してみました。 実際に処理する内
-
-
Call Python/Numpy Function within Metatrader 4
Github Link [bm url="https://github.com/fx-kirin/mt4-nump
-
-
Python での ポートフォリオの計算
Python でのポートフォリオの計算 ポートフォリオの計算について色々調べてみた。とりあえず使いたいって人はpo