[英]How to call Rust async method from Python?
我想在 Python 中使用 Rust 异步方法。 我正在尝试使用PyO3或rust-cpython 。
例如,对于同步 Rust 功能,我可以使用,
#[pyfunction]
fn myfunc(a: String) -> PyResult<String> {
let mut contents = String::new();
contents = a.to_string() + " appended";
Ok((contents))
}
#[pymodule]
fn MyModule(py: Python, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(urlshot))?;
Ok(())
}
对于异步方法,我该怎么做? 比如我想在Python中调用如下方法,
async fn hello_world() {
println!("hello, world!");
}
由于没有简单的方法来解决这个问题(至少,我没有找到),我将我的异步方法转换为同步方法。 并在 Python 方面将其称为,
async fn my_method(s: &str) -> Result<String, Error> {
// do something
}
#[pyfunction]
fn my_sync_method(s: String) -> PyResult<String> {
let mut rt = tokio::runtime::Runtime::new().unwrap();
let mut contents = String::new();
rt.block_on(async {
result = format!("{}", my_sync_method(&s).await.unwrap()).to_string();
});
Ok((result))
}
#[pymodule]
fn MyModule(py: Python, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(my_sync_method))?;
Ok(())
}
在Cargo.toml
文件中,我添加了以下依赖项,
[dependencies.pyo3]
git = "https://github.com/PyO3/pyo3"
features = ["extension-module"]
运行cargo build --release
后,会生成target/release/libMyModule.so
二进制文件。 将其重命名为MyModule.so
,现在可以从 Python 导入。
import MyModule
result = MyModule.my_sync_method("hello")
使用setuptools-rust ,我可以将其捆绑为普通的 Python package。
以上所有代码和命令都在新发布的 Linux Mint 20 上进行了测试。在 MacOS 上,二进制文件将为libMyModule.dylib
。
如果你想使用 Python 来控制 Rust 的异步 function,我认为它不会起作用(或者至少它很复杂,因为你需要连接两个不同future
机制)。 对于异步函数,Rust 编译器将维护一个 state 机器来管理在 await 的控制下正确运行的协程。 这是 Rust 应用程序的内部 state 并且 Python 无法触摸它。 同样Python解释器也有一个state机器不能被Rust触及。
我确实找到了有关如何使用 FFI 导出异步 function 的主题。 主要思想是将异步包装在BoxFuture
中,并让 C 控制将其返回到 Rust 的时间。 但是,您不能在 PyO3 中使用BoxFuture
,因为它的pyfunction
宏无法将 function 返回BoxFuture
转换为 Python 回调。 您可以尝试使用 FFI 创建一个库并使用 python 的 cffi 模块来加载它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.