在tokio::task中await Python协程时PyO3-asyncio无事件循环报错求助
解决Rust中tokio::spawn调用pyo3_asyncio时"no running event loop"错误
出现这个错误的核心原因是:tokio::spawn创建的新异步任务会在独立的执行上下文运行,原线程的Python事件循环并没有被自动关联到这个新任务中,导致pyo3_asyncio::into_future找不到可用的事件循环。
解决思路是手动将原Python事件循环的句柄传递到新任务,并在任务初始化时将其关联到当前tokio线程上下文,具体实现步骤如下:
1. 确保依赖配置正确
在Cargo.toml中添加正确的依赖及features,确保pyo3-asyncio与tokio集成:
[dependencies] pyo3 = { version = "0.21", features = ["auto-initialize"] } pyo3-asyncio = { version = "0.21", features = ["tokio-runtime"] } tokio = { version = "1.0", features = ["full"] }
2. Rust侧实现代码
use pyo3::prelude::*; use pyo3_asyncio::tokio::{get_current_loop, attach, into_future}; use tokio; #[pyfunction] async fn run_py_coroutine(py: Python, coro: &PyAny) -> PyResult<()> { // 获取当前线程关联的Python事件循环句柄 let loop_handle = get_current_loop(py)?; // 将事件循环句柄移入tokio异步任务 tokio::spawn(async move { // 在新任务中获取GIL(所有Python操作必须在GIL保护下进行) let py = Python::acquire_gil(); // 将事件循环关联到当前tokio任务的上下文 attach(py, &loop_handle).await?; // 转换Python协程为Rust Future并执行 let future = into_future(coro)?; future.await?; Ok(()) as PyResult<()> }).await??; // 等待任务完成并处理嵌套的Result Ok(()) } #[pymodule] fn rust_async_ext(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(run_py_coroutine, m)?)?; Ok(()) }
3. Python侧测试代码
import asyncio import rust_async_ext async def test_py_coro(): print("Python协程开始执行") await asyncio.sleep(1.0) print("Python协程执行完成") async def main(): await rust_async_ext.run_py_coroutine(test_py_coro()) asyncio.run(main())
关键细节说明
get_current_loop:获取当前持有GIL的线程所关联的Python事件循环句柄,这个句柄可以安全地移动到其他tokio任务中。attach:将传入的事件循环绑定到当前tokio任务的执行线程,确保后续pyo3-asyncio的API能找到正确的事件循环。- GIL获取:新任务中所有操作Python对象的步骤(包括
attach和into_future)都必须在GIL保护下进行,因此需要调用Python::acquire_gil()。
内容的提问来源于stack exchange,提问作者user25183845
相关产品推荐
相关产品推荐

