【问题标题】:Static lifetime annotation of a Pyo3-bound objectPyo3 绑定对象的静态生命周期注释
【发布时间】:2021-10-07 09:40:50
【问题描述】:

我正在尝试使用 Rust 及其 Tokio 运行时创建客户端,并使用 pyo3pyo3-asyncio 将其绑定到 python。举一个最小的例子,假设我想要一个连接到127.0.0.1:1234Client 类,并有一个处理通过套接字传入的数据的echo 方法。我希望该函数返回一个 Python 协程,这样我就可以在我的 Python 代码库中将它与 async 函数一起使用。示例用例:

import asyncio
from client import Client  # pyo3-bound rust code

c = Client()
asyncio.run(c.echo())

我已经关注了pyo3-asyncio 的文档并找到了this function。我写了这个(希望是最小的)sn-p 来重现这个问题:

use pyo3::prelude::*;

use tokio::runtime::Runtime;
use tokio::net::TcpStream;
use tokio::io::AsyncReadExt;


#[pyclass]
struct Client {
    rt: Runtime,
    stream: TcpStream,
}

#[pymethods]
impl Client {
    #[new]
    fn new() -> PyResult<Self> {
        let rt = Runtime::new().expect("Error creating runtime");
        let stream = rt.block_on(async {
            TcpStream::connect("127.0.0.1:1234").await
        })?;
        Ok(Self { rt, stream })
    }

    fn echo(&mut self) -> PyResult<PyObject> {
        let gil = Python::acquire_gil();
        let py = gil.python();
        pyo3_asyncio::tokio::into_coroutine(py, async move {
            loop {
                let mut vec = Vec::new();
                self.stream.read(&mut vec);
                println!("{:?}", vec);
            }
        })
    }
}


#[pymodule]
fn client(py: Python, m: &PyModule) -> PyResult<()> {
    let runtime = Runtime::new().expect("Tokio runtime error");
    m.add_class::<Client>()?;
    pyo3_asyncio::tokio::init(runtime);

    Ok(())
}

问题似乎是self,即Client,有一个匿名生命周期,但预计会有一个'static。编译器说:

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> src/lib.rs:28:60
   |
25 |       fn call_every_second(&mut self, callback: PyObject) -> PyResult<PyObject> {
   |                            --------- this data with an anonymous lifetime `'_`...
...
28 |           pyo3_asyncio::tokio::into_coroutine(py, async move {
   |  ____________________________________________________________^
29 | |             loop {
30 | |                 let mut vec = Vec::new();
31 | |                 self.stream.read(&mut vec);
32 | |                 println!("{:?}", vec);
33 | |             }
34 | |         })
   | |_________^ ...is captured here...
   |

有没有办法确保客户端的静态生命周期?也许我没有正确地解决问题?

【问题讨论】:

    标签: python rust rust-tokio pyo3


    【解决方案1】:

    into_coroutine() 函数需要一个'static 未来,所以你不能在未来借用Clientstream 字段。一种解决方法是更改​​Client,以便将stream 存储为Arc&lt;Mutex&lt;TcpStream&gt;&gt;

    struct Client {
        rt: Runtime,
        stream: Arc<Mutex<TcpStream>>, // using tokio::sync::Mutex
    }
    

    然后您可以通过Arc 授予into_coroutine() 对流的访问权限:

        // ...
        let stream = Arc::clone(&self.stream);
        pyo3_asyncio::tokio::into_coroutine(py, async move {
            loop {
                let mut vec = Vec::new();
                stream.lock().await.read(&mut vec).await?;
                println!("{:?}", vec);
            }
        })
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 2015-10-02
      • 2021-01-03
      相关资源
      最近更新 更多