You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyO3导出Rust异步函数供Python调用时future线程安全错误如何解决

问题根因

future cannot be sent between threads safely报错的核心是违反了pyo3_asyncio的约束:

  • pyo3_asyncio::tokio::future_into_py要求传入的Future必须实现Send trait,因为tokio多线程运行时会将Future调度到不同线程执行
  • 你将非Send的Python<'_>实例直接move进了async闭包,Python类型和当前线程的GIL绑定,不能跨线程传递,直接导致Future不满足Send约束
  • 额外的错误点:你不应该在跨线程的Future内部调用into_py转换Python对象,这一步操作需要持有GIL,在异步块内执行会导致线程安全问题
修复方案

直接修改导出函数即可:

#[pyfunction]
fn get_weather(py: Python) -> PyResult<&PyAny> {
    // 不要将py变量move进async闭包
    pyo3_asyncio::tokio::future_into_py(py, async move {
        // 异步块内只执行纯Rust逻辑,拿到原生Weather结构体
        let weather = get_weather().await.map_err(|e| {
            // 将Rust侧错误转换为Python可识别的异常,不要直接用unwrap
            pyo3::exceptions::PyRuntimeError::new_err(format!("获取天气失败: {}", e))
        })?;
        // 直接返回Rust原生结构体即可,PyO3会自动在GIL上下文中转换为Python对象
        Ok(weather)
    })
}
额外注意事项
  • 如果你用到的HTML解析逻辑有CPU密集型操作,建议将解析部分放到tokio::task::spawn_blocking中执行,避免阻塞异步运行时
  • 请确保Cargo.toml中依赖版本匹配,推荐用pyo3和pyo3-asyncio的0.20及以上稳定版本:
[dependencies]
pyo3 = { version = "0.20", features = ["extension-module"] }
pyo3-asyncio = { version = "0.20", features = ["tokio-runtime"] }
reqwest = { version = "0.11", features = ["native-tls", "tokio"] }
scraper = "0.18"
tokio = { version = "1.32", features = ["rt-multi-thread", "time"] }

内容的提问来源于stack exchange,提问作者alfex4936

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:12:04