Tokio非阻塞后台任务引发错误:`self`具有匿名生命周期`' _`,但需要满足`'static` 生命周期要求。

3
我有一个异步函数,想要在后台运行。这个函数是调用层次结构的一部分,而该结构没有使用异步调用。
我的调用层次结构如下:
struct Handler {}
impl Handler {

  pub async fn handle(&self) {
     /// does some stuff and updates internal caches
  }
}

struct Client_v2 {
  handler: Handler,
  rt: tokio::runtime::Runtime,
}

impl Client_v2 {

  fn do_work(&self) {
    let future = self.handler(handle);
    self.rt.spawn(future); // want this to run in background and not block! 
    // `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  }
}

据我所知,可能存在一个问题,即客户端 Client_v2 可能会超过其所有者的生命周期,从而导致此错误。

我该如何使生命周期有效?我需要创建线程并将对象移进和移出线程作用域吗?此函数被频繁调用。

2个回答

2
首先,handler不是可调用的,它是Client_v2的成员结构体。您需要通过点操作符访问它:self.handler.handle()
接下来是实际问题: Runtime::spawn要求提供的future必须是'static + Send,即不能借用数据,并且必须能够将其移动到另一个线程。 'static的要求是因为父线程可能在执行future的线程之前退出,因此必须确保任何给定给任务的数据至少与任务本身一样长寿。
它必须是Sendable,因为tokio运行时可以自由地在其线程池的线程之间移动spawned Futures。
您错误的相关要求是第一个,Handler::handle生成的未来不是'static,因为该函数以共享引用的形式借用了selfasync fn handle(&self)。调用此函数会产生一个Future + 'a,其中'a&'a self的寿命,即您可以将整个签名编写为fn handle<'a>(&'a self) -> impl Future<Output=()> + 'a + Send,但Runtime::spawn需要您返回impl Future<Output=()> + 'static + Send
为了证明您没有从&self中借用数据,您可以使用async {}块,并将返回类型明确说明为impl Future<Output = ()> + Send + 'static
  pub fn handle(&self) -> impl Future<Output = ()> + 'static + Send {
      async {}
  }

如果您需要在async块内访问来自&self的数据,则需要在async块外部生成它并将其移动到内部-否则生成的future将再次违反'static要求。

  pub fn handle(&self) -> impl Future<Output = ()> + 'static + Send {
      let owned_data = self.prepare_data();
      async move {
          let _owned_data = owned_data; // can now work with `owned_data`
      }
  }

好的解释! - Netwave

2

除了 @sebpuetz 的问题解释之外,在 Rust 中,您可以将类型包装在Arc中以能够共享其状态,因此您可以将其(Arc 的副本)移动到需要计算的未来:

struct Client_v2 {
  handler: Handler,
  rt: tokio::runtime::Runtime,
}

impl Client_v2 {

  pub async fn handle(&self) {
  }
  
  fn do_work(self: Arc<Self>) {
    let handler = self.clone();
    let future = async move { handler.handle().await; };
    self.rt.spawn(future);
  }
}

Playground


不确定这通常是如何处理的,但既然这个回答被 OP 接受了,可能把我的一些解释包含在下面会有意义? - sebpuetz
1
@sebpuetz,我会添加你的解释链接(尽管我认为很难错过,因为只有两个答案)。 - Netwave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接