简体   繁体   English

同步代码的异步包装器中的 Rust 生命周期

[英]Rust lifetimes in async wrapper for sync code

I am trying to create a Stream using a camera with a blocking capture method.我正在尝试使用具有阻塞捕获方法的相机创建Stream The blocking call is wrapped with blocking::unblock .阻塞调用用blocking::unblock包裹起来。

use futures::stream;
use rscam::{Camera, Config};

fn frame_stream() -> impl stream::Stream {
    let mut camera = Camera::new("/dev/video0").unwrap();

    camera.start(&Config {
        interval: (1, 30),
        resolution: (1280, 720),
        format: b"H264",
        ..Default::default()
    }).unwrap();

    stream::unfold(camera, |c| async move {
        let frame = blocking::unblock(|| c.capture().unwrap()).await;
        
        Some((frame, c))
    })
}

Compiling gives this error message:编译给出此错误消息:

error[E0373]: closure may outlive the current function, but it borrows `c`, which is owned by the current function
  --> src/lib.rs:15:39
   |
15 |         let frame = blocking::unblock(|| c.capture().unwrap()).await;
   |                                       ^^ - `c` is borrowed here
   |                                       |
   |                                       may outlive borrowed value `c`
   |
note: function requires argument type to outlive `'static`
  --> src/lib.rs:15:21
   |
15 |         let frame = blocking::unblock(|| c.capture().unwrap()).await;
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `c` (and any other referenced variables), use the `move` keyword
   |
15 |         let frame = blocking::unblock(move || c.capture().unwrap()).await;
   |                                       ++++

error[E0505]: cannot move out of `c` because it is borrowed
  --> src/lib.rs:17:22
   |
15 |         let frame = blocking::unblock(|| c.capture().unwrap()).await;
   |                     ------------------------------------------
   |                     |                 |  |
   |                     |                 |  borrow occurs due to use in closure
   |                     |                 borrow of `c` occurs here
   |                     argument requires that `c` is borrowed for `'static`
16 |         
17 |         Some((frame, c))
   |                      ^ move out of `c` occurs here

How can I guarantee to the compiler that the reference to c taken in the closure will still be valid?我如何向编译器保证闭包中对c的引用仍然有效? I assume it will be, since execution of the closure is awaited before c is returned.我认为它会是,因为在返回c之前等待执行闭包。

Solution解决方案

stream::unfold(camera, |c| async move {
    Some(
        blocking::unblock(|| {
            (c.capture().unwrap(), c)
        }).await
    )
})

You could move the camera into the inner closure, then return it once the frame capture is complete:您可以将相机移动到内部封闭中,然后在帧捕获完成后将其返回:

    stream::unfold(camera, |c| async move {
        Some(blocking::unblock(|| move {
            let frame = c.capture().unwrap()).await;
            (frame,c)
        })
    })

.await does not guarantee liveness. .await不保证活跃度。 This is the general problem ofscoped async tasks .这是作用域异步任务的普遍问题。 Futures can be canceled at any time.期货可以随时取消。 Consider:考虑:

let future = async {
    let local = 123;
    blocking::unblock(|| local).await;
};

// Poll `future`, but only once.
futures::block_on(async move { futures::poll!(future) });

We started a task using local data, then dropped the future.我们使用本地数据开始了一项任务,然后放弃了未来。 The task continues executing but the local data is gone.任务继续执行,但本地数据消失了。 For this reason, there is currently no sound way to expose an async API allowing using local data similar to scoped threads .出于这个原因,目前没有可靠的方法来公开异步 API,从而允许使用类似于作用域线程的本地数据。 You have to use 'static data, for example by wrapping in Arc .您必须使用'static数据,例如通过包装Arc

See also blocking issue #4 .另请参阅blocking问题 #4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM