如何从Python中调用Rust函数?

sxpgvts3  于 2024-01-08  发布在  Python
关注(0)|答案(3)|浏览(177)

我想在Python中使用一个Rust fixc方法。我正在尝试使用PyO3rust-cpython
例如,对于同步Rust函数,我可以使用,

  1. #[pyfunction]
  2. fn myfunc(a: String) -> PyResult<String> {
  3. let mut contents = String::new();
  4. contents = a.to_string() + " appended";
  5. Ok((contents))
  6. }
  7. #[pymodule]
  8. fn MyModule(py: Python, m: &PyModule) -> PyResult<()> {
  9. m.add_wrapped(wrap_pyfunction!(urlshot))?;
  10. Ok(())
  11. }

字符串
对于python方法,我该怎么做呢?例如,我想在Python中调用下面的方法,

  1. async fn hello_world() {
  2. println!("hello, world!");
  3. }

sg24os4d

sg24os4d1#

由于没有简单的方法来解决这个问题(至少,我没有找到),我将我的python c方法转换为sync方法。并在Python端将其称为:

  1. async fn my_method(s: &str) -> Result<String, Error> {
  2. // do something
  3. }
  4. #[pyfunction]
  5. fn my_sync_method(s: String) -> PyResult<String> {
  6. let mut rt = tokio::runtime::Runtime::new().unwrap();
  7. let mut contents = String::new();
  8. rt.block_on(async {
  9. result = format!("{}", my_sync_method(&s).await.unwrap()).to_string();
  10. });
  11. Ok((result))
  12. }
  13. #[pymodule]
  14. fn MyModule(py: Python, m: &PyModule) -> PyResult<()> {
  15. m.add_wrapped(wrap_pyfunction!(my_sync_method))?;
  16. Ok(())
  17. }

字符串
Cargo.toml文件中,我添加了以下依赖项:

  1. [dependencies.pyo3]
  2. git = "https://github.com/PyO3/pyo3"
  3. features = ["extension-module"]


运行cargo build --release后,生成target/release/libMyModule.so二进制文件。将其转换为MyModule.so,现在可以从Python导入。

  1. import MyModule
  2. result = MyModule.my_sync_method("hello")


使用setuptools-rust,我可以将其捆绑为普通的Python包。
上述所有代码和命令都在新发布的Linux Mint 20上进行了测试。在MacOS上,二进制文件将是libMyModule.dylib

展开查看全部
l2osamch

l2osamch2#

如果你想用Python来控制Rust的python c函数,我认为这是行不通的。(或者至少它是非常复杂的,因为你需要连接两个不同的future机制).对于mixc函数,Rust编译器将维护一个状态机来管理在await的控制下正确运行的协程。这是Rust应用程序的内部状态,Python无法触及它。类似地,Python解释器也有一个Rust不能触及的状态机。
我确实找到了this topic关于如何使用FFI导出一个masc函数。主要思想是将masc Package 在BoxFuture中,让C控制返回Rust的时间。然而,你不能在PyO3中使用BoxFuture,因为它的pyfunction宏不能将函数返回BoxFuture转换为Python回调。你可以尝试使用FFI创建一个库,并使用python的cffi模块来加载它。

fkaflof6

fkaflof63#

我在pyo 3文档中找到了这个教程:https://pyo3.rs/v0.20.0/ecosystem/async-await
如果你需要调用一个从Python返回结果(String,None等)的Rust函数,似乎你需要访问Python的GIL:
lib.rs

  1. use pyo3::prelude::*;
  2. async fn rust_sleep() {
  3. async_std::task::sleep(std::time::Duration::from_secs(1)).await;
  4. }
  5. #[pyfunction]
  6. fn call_rust_sleep(py: Python<'_>) -> PyResult<&PyAny> {
  7. pyo3_asyncio::async_std::future_into_py(py, async move {
  8. rust_sleep().await;
  9. Ok(Python::with_gil(|py| py.None()))
  10. })

字符串
example.py

  1. from example import call_rust_sleep
  2. async def rust_sleep():
  3. await call_rust_sleep()


要从函数返回一个字符串:

  1. Ok(result) => Ok(Python::with_gil(|py| "hello world".to_string()))

展开查看全部

相关问题