Asynchronous 如何在不使用任何外部依赖项的情况下执行异步/等待函数?

Asynchronous 如何在不使用任何外部依赖项的情况下执行异步/等待函数?,asynchronous,rust,future,Asynchronous,Rust,Future,我试图创建一个最简单的示例,它可以得到async fn hello(),最终打印出hello World。这应该在没有任何外部依赖的情况下发生,如tokio,只是普通的锈迹和std。如果我们不使用不安全的就可以完成此任务,则可获得额外积分 #![feature(async_await)] async fn hello() { println!("Hello, World!"); } fn main() { let task = hello(); // Somethi

我试图创建一个最简单的示例,它可以得到
async fn hello()
,最终打印出
hello World。这应该在没有任何外部依赖的情况下发生,如
tokio
,只是普通的锈迹和
std
。如果我们不使用
不安全的
就可以完成此任务,则可获得额外积分

#![feature(async_await)]

async fn hello() {
    println!("Hello, World!");
}

fn main() {
    let task = hello();

    // Something beautiful happens here, and `Hello, World!` is printed on screen.
}
  • 我知道
    async/await
    仍然是一项夜间功能,在可预见的将来可能会有所改变
  • 我知道未来会有大量的
    实现,我知道
    东京
    的存在
  • 我只是想让自己了解标准图书馆未来的内部运作
我无助、笨拙的努力 我模糊的理解是,首先,我需要
确定
任务。所以我继续前进

let pinned_task = Pin::new(&mut task);
但是

这显然不是我应该做的。即便如此,假设我得到了
密码
ned
未来
。现在我需要
poll()
。为此,我需要一个
唤醒器


所以我试着四处看看如何弄到一个
叫醒器
。从表面上看,获得
唤醒器
的唯一方法似乎是使用另一个
新的
来接受
唤醒器
。从那里我得到了,从那里开始,我蜷缩在地板上开始哭泣。

这一部分的期货合约不打算被很多人执行。我在中看到的粗略估计可能会有10个左右的实际实现

也就是说,您可以填写执行器的基本方面,这些方面受到以下所需函数签名的极大限制:

async fn hello() {
    println!("Hello, World!");
}

fn main() {
    drive_to_completion(hello());
}

use std::{
    future::Future,
    ptr,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

fn drive_to_completion<F>(f: F) -> F::Output
where
    F: Future,
{
    let waker = my_waker();
    let mut context = Context::from_waker(&waker);

    let mut t = Box::pin(f);
    let t = t.as_mut();

    loop {
        match t.poll(&mut context) {
            Poll::Ready(v) => return v,
            Poll::Pending => panic!("This executor does not support futures that are not ready"),
        }
    }
}

type WakerData = *const ();

unsafe fn clone(_: WakerData) -> RawWaker {
    my_raw_waker()
}
unsafe fn wake(_: WakerData) {}
unsafe fn wake_by_ref(_: WakerData) {}
unsafe fn drop(_: WakerData) {}

static MY_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);

fn my_raw_waker() -> RawWaker {
    RawWaker::new(ptr::null(), &MY_VTABLE)
}

fn my_waker() -> Waker {
    unsafe { Waker::from_raw(my_raw_waker()) }
}
async fn hello(){
println!(“你好,世界!”);
}
fn main(){
驱动到完成(hello());
}
使用std::{
未来,
ptr,
任务:{上下文,轮询,RawWaker,RawWakerVTable,Waker},
};
fn驱动到完成(f:f)->f::输出
哪里
F:未来,
{
让waker=my_waker();
让mut context=context::from_waker(&waker);
设mut t=Box::pin(f);
设t=t.as_mut();
环路{
匹配t.poll(&mut上下文){
Poll::Ready(v)=>返回v,
Poll::Pending=>panic!(“此执行者不支持未准备好的期货”),
}
}
}
键入WakerData=*const();
不安全的fn克隆(uu3;:WakerData)->RawWaker{
我的原始唤醒器()
}
不安全的fn唤醒(uuiq:WakerData){}
不安全的fn wake_by_ref(u:WakerData){}
不安全的fn丢弃(uuxOkerData){}
静态MY_VTABLE:RawWakerTable=RawWakerTable::new(克隆、唤醒、唤醒、删除);
fn my_raw_waker()->RawWaker{
RawWaker::new(ptr::null(),&MY_VTABLE)
}
fn my_waker()->waker{
不安全{Waker::from_raw(my_raw_Waker())}
}
从一开始,我们看到我们需要一个美好的未来和一个美好的未来<代码>上下文
是从需要的创建的。一个
RawWaker
需要一个。我们以最简单的方式制作所有这些作品:

  • 由于我们不试图支持
    NotReady
    案例,因此我们永远不需要为该案例实际做任何事情,反而会产生恐慌。这也意味着
    wake
    的实现可以是无操作的

  • 由于我们不想提高效率,我们不需要为我们的唤醒器存储任何数据,因此
    克隆
    删除
    基本上也可以是无操作

  • 锁定未来最简单的方法是将它框起来,但这并不是最有效的方法



如果您想支持
NotReady
,最简单的扩展就是拥有一个繁忙的循环,即永远轮询。一个稍微更有效的解决方案是使用一个全局变量,该变量指示有人调用了
wake
,并阻止该变量变为true

太棒了!小问题:
async/await
功能(因此才有了
![feature(async\u await)]
),但
std::Future
接口现在稳定了,对吗?@MatteoMonti<代码>未来
已在夜间编译器中稳定,但这种稳定尚未进入beta频道。它肯定还没有达到任何发布的生锈版本。@MatteoMonti
未来的
将稳定(在1.36.0中),但不稳定(在当前的1.34.0中)。您需要使用异步fn hellow
功能。
let pinned_task = unsafe {
    Pin::new_unchecked(&mut task)
};
async fn hello() {
    println!("Hello, World!");
}

fn main() {
    drive_to_completion(hello());
}

use std::{
    future::Future,
    ptr,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

fn drive_to_completion<F>(f: F) -> F::Output
where
    F: Future,
{
    let waker = my_waker();
    let mut context = Context::from_waker(&waker);

    let mut t = Box::pin(f);
    let t = t.as_mut();

    loop {
        match t.poll(&mut context) {
            Poll::Ready(v) => return v,
            Poll::Pending => panic!("This executor does not support futures that are not ready"),
        }
    }
}

type WakerData = *const ();

unsafe fn clone(_: WakerData) -> RawWaker {
    my_raw_waker()
}
unsafe fn wake(_: WakerData) {}
unsafe fn wake_by_ref(_: WakerData) {}
unsafe fn drop(_: WakerData) {}

static MY_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);

fn my_raw_waker() -> RawWaker {
    RawWaker::new(ptr::null(), &MY_VTABLE)
}

fn my_waker() -> Waker {
    unsafe { Waker::from_raw(my_raw_waker()) }
}