如何在 poll() 方法中调用异步函数?

Anu*_*aki 5 future rust

我想在 Future::poll() 中调用异步函数,但 poll() 不是异步函数,所以我必须轮询异步 fn,但出现错误:

error[E0599]: no method named `poll` found for opaque type `impl Future` in the current scope
  --> src\lib.rs:18:22
   |
18 |         let a = fut1.poll(cx);
   |                      ^^^^ method not found in `impl Future`
Run Code Online (Sandbox Code Playgroud)

我尝试 Pin::new(async fn()).poll(),得到另一个错误:

error[E0277]: `from_generator::GenFuture<[static generator@src\lib.rs:33:23: 36:2 {ResumeTy, u64, Duration, impl Future, ()}]>` cannot be unpinned
  --> src\lib.rs:22:23
   |
22 |         let pinfut1 = Pin::new(&mut fut1);
   |                       ^^^^^^^^ within `impl Future`, the trait `Unpin` is not implemented for `from_generator::GenFuture<[static generator@src\lib.rs:33:23: 36:2 {ResumeTy, u64, Duration, impl Future, ()}]>`
...
33 | async fn fn1() -> i32 {
   |                   --- within this `impl Future`
Run Code Online (Sandbox Code Playgroud)

代码:

use std::future::Future;
use std::task::{Context, Poll};
use std::pin::Pin;
use std::sync::{Arc,Mutex};

#[pin_project::pin_project]
struct Person<'a> {
    name: &'a str,
    age: i32,
}

impl<'a> Future for Person<'a> {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut this = self.project();
        *this.age += 1;

        // error: poll() ^^^^ method not found in `impl Future`
        // let mut fut1 = fn1();
        // let a = fut1.poll(cx);

        // error: Pin::new() ^^^^^^^^ within `impl Future`, the trait `Unpin` is not implemented for `from_generator::GenFuture
        let mut fut1 = fn1();
        let pinfut1 = Pin::new(&mut fut1);
        let a = pinfut1.poll(cx);

        if *this.age > 4 {
            Poll::Ready(*this.age)
        } else {
            Poll::Pending
        }
    }
}

async fn fn1() -> i32 {
    async_std::task::sleep(std::time::Duration::from_secs(2)).await;
    123
}

fn main() {
    let p1 = Person {name: "jack", age: Default::default()};
    async_std::task::block_on(async {
        let a = p1.await;
        dbg!(a);
    });
}
Run Code Online (Sandbox Code Playgroud)

box*_*dot 5

要调用pollwhichfut1返回的fn1,您需要获取 a Pin<&mut F>,其中F是 future 的类型fut1。至少有三种可能性可以做到这一点(我省略了unsafe):

  1. 如果fut1实现了Unpin,你可以打电话Pin::new
  2. 您可以fut1使用Box::pin, 或
  3. 您可以fut1使用宏固定堆栈futures_util::pin_mut!

有时有点难以弄清楚是否Unpin已实现,如果没有,那么为什么。fn1这里的一般建议是对into:的签名进行脱糖fn fn1() -> impl Future<Output = usize> + Unpin。编译器错误通常会更精确。

顺便说一句,宏的实现pin_mut!有一些有用的见解。它使用 Rust 类型系统来移动 future 并隐藏变量,使其无法再被访问,通过这样做,它保证Pin::new_unchecked满足 的不变量,因此可以调用它。


Anu*_*aki -3

我已将代码更改为以下内容,编译成功,但结果不正确:Future::poll() 中将通过 poll 方式调用 async fn,但 async fn 中的 .await 语句将永远被阻塞。

\n
use std::future::Future;\nuse std::task::{Context, Poll};\nuse std::pin::Pin;\nuse std::sync::{Arc,Mutex};\nuse futures::FutureExt;\n\n#[pin_project::pin_project]\nstruct Person<'a> {\n    name: &'a str,\n    age: i32,\n}\n\nimpl<'a> Future for Person<'a> {\n    type Output = i32;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let mut this = self.project();\n        *this.age += 10;\n\n        let mut fut1 = fn1();\n        let pinfut1 =  Pin::new(&mut fut1);\n        //let pinfut1 = unsafe { Pin::new_unchecked(&mut fut1) };\n        pinfut1.poll(cx)\n    }\n}\n\nfn fn1() -> impl Future<Output=i32> + Unpin {\n    async {\n        dbg!("sleep start!"); // execute here!\n        async_std::task::sleep(std::time::Duration::from_secs(5)).await; //  <--- blocked here ?\n        dbg!("sleep done!"); // Never execute here\xef\xbc\x81\n        123\n    }.boxed()\n}\n\nfn main() {\n    let p1 = Person {name: "jack", age: Default::default()};\n    async_std::task::block_on(async {\n        let a = p1.await;\n        dbg!(a); // Never execute here! // expect 123\n    });\n    std::thread::park();\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

  • 需要做哪些保证才能确保这个不安全的区块是安全的?总体来说安全吗?或者仅对于这个例子是安全的? (5认同)