ABOUT ME

-

Total
-
  • Rust: PyO3 파이썬 모듈 Rust 언어로 만들기
    컴퓨터/Rust 2021. 4. 24. 19:52
    728x90
    반응형

    Rust

    PyO3

     

    Rust Programming Language

    A language empowering everyone to build reliable and efficient software.

    www.rust-lang.org

     

    1. 소개

    CPython API를 통해 Python 모듈을 빠르게 만드는 방법과 같이 Rust로 만들 수 있다.

     

    Python 모듈 C언어로 만들기

    Python 모듈 1. 소개 전 ctype으로 C언어 코딩 실행하기와 비슷한데 실제로 pip으로 설치할 수 있는 파이썬 패키지를 C언어로 만들어 볼 것이다. Python Github의 C 파일들은 보면 문법이 어느 정도 감이

    www.seokdev.site

    Rust로 만들 경우 몇 % 의 성능 향상이 있을진 모른다. gil 사용 안 한 parallelism 성능은 다음과 같이 나와있다.

    (단순 단어 세는 프로그램, rust로 만들어 쓸 경우가 훨씬 빠르다.)

    -------------------------------------------------------------------------------------------------- benchmark: 4 tests -------------------------------------------------------------------------------------------------
    Name (time in ms)                                          Min                Max               Mean            StdDev             Median               IQR            Outliers       OPS            Rounds  Iterations
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    test_word_count_rust_parallel                           1.7315 (1.0)       4.6495 (1.0)       1.9972 (1.0)      0.4299 (1.0)       1.8142 (1.0)      0.2049 (1.0)         40;46  500.6943 (1.0)         375           1
    test_word_count_rust_sequential                         7.3348 (4.24)     10.3556 (2.23)      8.0035 (4.01)     0.7785 (1.81)      7.5597 (4.17)     0.8641 (4.22)         26;5  124.9457 (0.25)        121           1
    test_word_count_rust_sequential_twice_with_threads      7.9839 (4.61)     10.3065 (2.22)      8.4511 (4.23)     0.4709 (1.10)      8.2457 (4.55)     0.3927 (1.92)        17;17  118.3274 (0.24)        114           1
    test_word_count_python_sequential                      27.3985 (15.82)    45.4527 (9.78)     28.9604 (14.50)    4.1449 (9.64)     27.5781 (15.20)    0.4638 (2.26)          3;5   34.5299 (0.07)         35           1
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    

     

    2. 예제

    setup.py

    setuptools_rust를 따로 설치해야 함

    pip install setuptools setuptools_rust
    python setup.py install
    from setuptools import setup
    from setuptools_rust import Binding, RustExtension
    
    
    def call_setup():
        setup(
            name="module_name",
            version="0.0.1",
            description="PyPI 설명",
            # long_description=open("README.rst", encoding="utf-8").read(),
            # long_description_content_type="text/x-rst",
            keywords="rust",
            author="Seok Won",
            author_email="@kakao.com",
            maintainer="",
            maintainer_email="@kakao.com",
            python_requires=">=3.5",
            license="MIT",
            rust_extensions=[RustExtension("module_name", binding=Binding.PyO3)],
            classifiers=[
                "Development Status :: 3 - Alpha",
                "Intended Audience :: Developers",
                "License :: OSI Approved :: MIT License",
                "Operating System :: OS Independent",
                "Programming Language :: Python :: 3",
                "Programming Language :: Python :: 3.5",
                "Programming Language :: Python :: 3.6",
                "Programming Language :: Python :: 3.7",
                "Programming Language :: Python :: 3.8",
                "Programming Language :: Python :: 3.9",
                "Programming Language :: Rust",
            ],
            zip_safe=False,
        )
    
    
    if __name__ == "__main__":
        call_setup()

     

    lib.rs

    pymethod,  pyclass 등의 attributes를 사용해서 pymodule에 알려주어야 함

    cargo run이 아닌, python setup.py install을 할 때 알아서 빌드하고 설치된다.

    extern crate pyo3;
    
    use pyo3::prelude::*;
    use pyo3::types::PyList;
    use pyo3::PyObjectProtocol;
    
    #[pyclass(subclass)]
    pub struct Human {
        #[pyo3(get)]
        name: String,
        #[pyo3(get)]
        age: u8,
        #[pyo3(get)]
        salary: u32,
    }
    
    #[pymethods]
    impl Human {
        #[new]
        fn new(name: String, age: u8, salary: u32) -> Self {
            Human { name, age, salary }
        }
    
        fn promote(&mut self, salary: u32) {
            self.salary = salary;
        }
    
        fn string(&self) -> PyResult<String> {
            let str = format!("I am {}!", self.name).to_string();
            Ok(str)
        }
    }
    
    #[pyproto]
    impl PyObjectProtocol for Human {
        fn __str__(&self) -> PyResult<&'static str> {
            Ok(format!("Human: name({})", self.name))
        }
    
        fn __repr__<'a>(&'a self) -> PyResult {
            Ok(format!("Human name: {}", self.name))
        }
    }
    
    #[pyfunction]
    fn bubble(_py: Python, array: &PyList) -> PyResult<()> {
        let mut count = 0;
        let mut is_sorted = false;
        let n = array.len() - 1;
    
        while !is_sorted {
            is_sorted = true;
            for i in 0..(n - count) as isize {
                let first = array.get_item(i);
                let second = array.get_item(i + 1);
    
                match first.compare(second).unwrap() {
                    Ordering::Greater => {
                        array.set_item(i, second)?;
                        array.set_item(i + 1, first)?;
                        is_sorted = false;
                    }
                    _ => {}
                }
            }
    
            count += 1;
        }
    
        Ok(())
    }
    
    #[pymodule]
    fn rust_sort(_py: Python, m: &PyModule) -> PyResult<()> {
        m.add_class::<Human>()?;
        m.add_function(wrap_pyfunction!(bubble, m)?)?;
        Ok(())
    }
    

     

    test.py

    rust_sort로 만들고 위의 bubble 함수와 Human 클래스를 import 했다.

    from rust_sort import bubble, Human
    
    
    def bubble_test():
        a = [5, -2, 3, 0, 11]
        bubble(a)
        print(a)  # [-2, 0, 3, 5, 11]
    
    
    def class_test():
        print()
        human = Human("A1", 37, 1200)
        print(human.salary)  # 1200
        human.promote(1500)
        print(human.salary)  # 1500
        print(human.string())  # I am A1!
    
    
    if __name__ == "__main__":
        bubble_test()
        class_test()
    

     

    참고

    공식 문서: pyo3.rs/

     

    https://pyo3.rs/

     

    pyo3.rs

    PyO3 Github (여러 가지 example을 볼 수 있음): github.com/PyO3/pyo3

     

    PyO3/pyo3

    Rust bindings for the Python interpreter. Contribute to PyO3/pyo3 development by creating an account on GitHub.

    github.com

    위 소스 Github 링크: github.com/Alfex4936/Rust-PyO3-Example

     

    Alfex4936/Rust-PyO3-Example

    Building a python module in Rust language (template) - Alfex4936/Rust-PyO3-Example

    github.com

     

    728x90

    댓글