Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping a Simple Function Part ➀

Overview

  1. It is not preferable in terms of speed to write the algorithm in Pyhton ~
  2. Alright, look for something written around C, C ++ and call it from Python to speed it up.
  3. I can't find a good library,
  4. Oh, if it was written in a language called Rust
  5. Can Rust be called from Python? ??

Ultimate goal

So, I've written a "Cython" tutorial for calling C ++ libraries from Python to speed things up.

From this time, I will write a tutorial of a library called "PyO3" to call Rust from Python and speed it up.

The ultimate goal is Being able to easily call functions and classes (like things?) Written in rust from python is.

This PyO3 (git is here) is in the middle of development and version updates are (probably) at a tremendous rate.

This goal

In the first place, starting from the state of Rust's first look, I touched PyO3 with the goal of being able to call functions written in Rust from Python.

There are some commentary articles on Kita and other blogs. -[Rust] Create Python package with PyO3 -Link Python and Rust with Pyo3 -Run Rust module from Python (PyO3) -Write a Python extension module using Python and Rust

This time, Run Rust module from Python (PyO3) I'd like to borrow your code, add setup.py to it, and call a function written in Rust from Python.

procedure

Install rust

When you execute the first line, you will be asked about the installation with 3 choices, but I think that there is no problem selecting 1 of the default installation.

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

Install rust nightly

You will need it to use PyO3. Is it something like a beta version that contains a lot of crates under development?

Check the version I will use this version this time.

$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

Create a rust project

Create a project for the library by adding --lib. This time, the project name is ʻexample`.

cargo new --lib example

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

The folder structure looks like this.

Set Cargo.toml

One of the things that Rust is said to be better than C ++ is the ease of managing libraries. I write the necessary libraries in Cargo.toml, but it's much easier and easier to read than 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"]

This time I used pyo3 as a library and The target library to create is test_library.

That is, in Python

test.py


import test_library

I want to write like this.

Create a function in Rust

Try copying sutras for the time being

The code is Run Rust module from Python (PyO3) I brought all of his stuff. It's an implementation of the Eratosthenes sieve.


//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)
}



I don't have the ability to explain Rust's syntax in detail, so Let's assume that this function is correct, and explain how it is wrapped in a form that can be called from Python.

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

If you look at First, the decorator of `` `# [pyfunction] ``` declares that the argument or return value of this function will contain a Python object parsed by PyO3.

This get_prime_numbers function takes int32 as an argument and returns a list of prime numbers less than that. At this time, the return value is `PyResult <Vec <i32 >>`, This PyResult comes from ```use pyo3 :: prelude :: *;` ``.

Also, `Vec <i32>` is as shown in the type correspondence table below, and is converted to Python List type by PyResut.

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

Quoted from [Rust] Create Python package with PyO3

Also the last

Ok(primes)

Is converting `Vec``` to `list```.

Summary

I'm sorry that if you end here, you'll end up with a copy of most of the references. I will separate it here once.

In summary,

--I installed Rust. --Created a project for Rust's library. --Written Cargo.toml. --I copied the function and confirmed the type conversion of Rust-> Python.

That's it.

Next, add lib.rs, add setup.py, and actually compile it as an object file of the library.

This time around here.

end.

Recommended Posts

Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping a Simple Function Part ➀
Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping a Simple Function Part ➁
Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping Classes Part ➀
Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping Classes Part ➁
[Python] How to call a c function from python (ctypes)
Call a Python function from p5.js.
Simple code to call a python program from Javascript on EC2
C language to see and remember Part 3 Call C language from Python (argument) c = a + b
Consider a conversion from a Python recursive function to a non-recursive function
How to call a function
[Python Kivy] How to create a simple pop up window
From setting up a Rust environment to running Hello World
Go language to see and remember Part 8 Call GO language from Python
Don't write Python if you want to speed it up with Python
[Python] Hit Keras from TensorFlow and TensorFlow from c ++ to speed up execution
[Road to Python Intermediate] Call a class instance like a function with __call__
Call dlm from python to run a time-varying coefficient regression model
[Python] A simple function to find the center coordinates of a circle
Everything from building a Python environment to running it on Windows
Call Matlab from Python to optimize
Numba to speed up as Python
Python-dynamically call a function from a string
How to speed up Python calculations
Introduction and usage of Python bottle ・ Try to set up a simple web server with login function
I want to pass an argument to a python function and execute it from PHP on a web server
C language to see and remember Part 2 Call C language from Python (argument) string
C language to see and remember Part 1 Call C language from Python (hello world)
C language to see and remember Part 4 Call C language from Python (argument) double
C language to see and remember Part 5 Call C language from Python (argument) Array
Send a message from Python to Slack
A simple IDAPython script to name a function
Call a command from Python (Windows version)
[Python] I tried to get the type name as a string from the type function
Python program is slow! I want to speed up! In such a case ...
Send a message from Slack to a Python server
Set up a simple HTTPS server in Python 3
Edit Excel from Python to create a PivotTable
How to open a web browser from python
To execute a Python enumerate function in JavaScript
How to create a function object from a string
How to generate a Python object from JSON
Call a Python script from Embedded Python in C ++ / C ++
Set up a simple SMTP server in Python
[Go] How to write or call a function
[Python] Do your best to speed up SQLAlchemy
An easy way to call Java from Python
On a PC that cannot boot from NVMe, move / usr etc. to NVMe to speed up
Understand Python yield If you put yield in a function, it will change to a generator
[It's not too late to learn Python from 2020] Part 2 Let's create a Python development environment
A mechanism to call a Ruby method from Python that can be done in 200 lines