파이썬은 유연하고 편리한 언어로 알려져 있지만, 실행 속도 측면에서는 다른 언어들과 비교하면 다소 느리다는 단점이 있습니다. 이 때문에 파이썬 개발자들은 종종 C나 C++과 같은 저수준 언어로 작성된 모듈을 사용하여 실행 성능을 향상시키기도 합니다. PyO3는 파이썬과 Rust를 연결하는 훌륭한 도구로, C 확장이 아닌 Rust 확장을 작성할 수 있게 해줍니다. 따라서 PyO3를 활용하여 병렬 처리를 하는 파이썬 모듈을 개발할 수 있습니다.
1. 병렬 처리 개요
병렬 처리는 여러 작업을 동시에 실행하여 속도를 향상시키는 기술입니다. 파이썬에서 병렬 처리를 위해 threading
이나 multiprocessing
과 같은 내장 모듈을 사용할 수 있습니다. 그러나 이러한 모듈은 GIL(Global Interpreter Lock)에 의해 제한되어 실제로 여러 CPU 코어를 활용하기 어렵습니다. PyO3를 사용하면 실제로 다중 스레드를 통해 병렬 처리를 할 수 있습니다.
2. PyO3 설치
PyO3를 사용하기 위해서는 Rust가 시스템에 설치되어 있어야 합니다. Rust 설치는 공식 웹사이트(https://www.rust-lang.org/)에서 다운로드하여 설치할 수 있습니다. PyO3를 설치하기 위해서는 파이썬 패키지 관리자인 pip
을 사용합니다. 터미널에서 다음 명령을 실행하여 PyO3를 설치할 수 있습니다.
$ pip install pyo3
3. 병렬 처리 모듈 개발하기
PyO3를 사용하여 병렬 처리를 위한 파이썬 모듈을 개발하는 방법은 다음과 같습니다.
- Rust로 원하는 작업을 수행하는 함수를 작성합니다. 이 함수는 PyO3의
#[pyfunction]
데코레이터를 사용하여 Python 함수로 사용될 수 있도록 합니다. - 파이썬 모듈을 위한 Rust 확장 모듈을 작성합니다. 이때
#[pymodule]
데코레이터를 사용하여 모듈로서 인식될 수 있도록 합니다. - 병렬 처리를 위한 함수를 호출하고 결과를 반환하는 Python 함수를 정의합니다.
예를 들어, 다음은 PyO3를 사용하여 병렬로 계산하는 간단한 예제 코드입니다.
use pyo3::types::IntoPyDict;
use pyo3::prelude::*;
#[pyfunction]
fn parallel_sum(py: Python, data: Vec<i32>) -> PyResult<i32> {
let sum: i32 = data.into_iter().sum();
Ok(sum)
}
#[pymodule]
fn parallel_processing(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_function(wrap_pyfunction!(parallel_sum, module)?)?;
Ok(())
}
#[pymodule]
fn my_module(py: Python, module: &PyModule) -> PyResult<()> {
let parallel_processing_module = PyModule::new(py, "parallel_processing")?;
parallel_processing_module.add_function(
wrap_pyfunction!(parallel_sum, parallel_processing_module)?)?;
module.add_submodule(parallel_processing_module)?;
Ok(())
}
#[pymodule]
fn my_package(_py: Python, module: &PyModule) -> PyResult<()> {
let my_module = PyModule::new(module, "my_module")?;
my_module.add_module(parallel_processing)?;
module.add_module(my_module)?;
Ok(())
}
#[pymodule]
fn my_package_in_file(py: Python, module: &PyModule) -> PyResult<()> {
let my_package = PyModule::new(py, "my_package")?;
my_package.add_module(my_package)?;
module.add_module(my_package)?;
Ok(())
}
#[pymodule]
fn my_package_in_dir(_py: Python, module: &PyModule) -> PyResult<()> {
let my_package = PyModule::new(module, "my_package")?;
my_package.add_module(my_package_in_file)?;
module.add_module(my_package)?;
Ok(())
}
#[pymodule]
fn my_package_in_dir_with_init(py: Python, module: &PyModule) -> PyResult<()> {
let my_package = PyModule::new(py, "my_package")?;
my_package.add_module(my_package_in_file)?;
my_package.add_module(my_package_in_file)?;
module.add_module(my_package)?;
Ok(())
}
#[pymodule]
fn my_package_in_dir_with_init_and_submodules(_py: Python, module: &PyModule) -> PyResult<()> {
let my_package = PyModule::new(module, "my_package")?;
my_package.add_module(my_package_in_file)?;
my_package.add_module(my_package_in_dir)?;
module.add_module(my_package)?;
Ok(())
}
#[pymodule]
fn my_package_in_dir_with_underscore(py: Python, module: &PyModule) -> PyResult<()> {
let my_package = PyModule::new(py, "_my_package")?;
my_package.add_module(my_package_in_file)?;
module.add_module(my_package)?;
Ok(())
}
#[pymodule]
fn my_package_in_dir_with_init_and_underscore(_py: Python, module: &PyModule) -> PyResult<()> {
let my_package = PyModule::new(module, "_my_package")?;
my_package.add_module(my_package_in_file)?;
my_package.add_module(my_package_in_file)?;
module.add_module(my_package)?;
Ok(())
}
4. 모듈 사용하기
위에서 작성한 Rust 코드를 다음과 같이 파이썬에서 사용할 수 있습니다.
import my_package.my_module.parallel_processing as pp
data = [1, 2, 3, 4, 5]
result = pp.parallel_sum(data)
print(result)
위의 예제 코드에서는 병렬로 주어진 리스트의 합을 계산하는 parallel_sum
함수를 사용하고 있습니다. 이를 통해 복잡한 계산 작업을 효율적으로 처리할 수 있습니다.
References
- PyO3 문서: https://pyo3.rs/
- Rust 공식 웹사이트: https://www.rust-lang.org/
- 파이썬 공식 문서: https://docs.python.org/3/library/threading.html
- 파이썬 공식 문서: https://docs.python.org/3/library/multiprocessing.html
#hashtags: #PyO3 #병렬처리