gpt4 book ai didi

asynchronous - 如何在不使用任何外部依赖项的情况下执行异步/等待功能?

转载 作者:行者123 更新时间:2023-11-29 08:04:43 24 4
gpt4 key购买 nike

我正在尝试创建最简单的示例,使 async fn hello() 最终打印出 Hello World!。这应该在没有任何外部依赖的情况下发生,比如 tokio,只是简单的 Rust 和 std。如果我们能够在不使用 unsafe 的情况下完成它,则会加分。

#![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 仍然是夜间功能,并且在可预见的 future 可能会发生变化。
  • 我知道有很多Future 实现,我知道tokio 的存在。
  • 我只是想自学标准库 futures 的内部工作原理。

我无助、笨拙的努力

我的模糊理解是,首先,我需要Pin 任务。所以我继续前进

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

但是

the trait `std::marker::Unpin` is not implemented for `std::future::GenFuture<[static generator@src/main.rs:7:18: 9:2 {}]>`

所以我想,当然,我可能需要 Box 它,所以我确定它不会在内存中移动。有点令人惊讶的是,我得到了同样的错误。

到目前为止我能得到的是

let pinned_task = unsafe {
Pin::new_unchecked(&mut task)
};

这显然不是我应该做的事情。即便如此,假设我得到了 Pinned Future。现在我需要以某种方式poll() 它。为此,我需要一个 Waker

所以我试着四处寻找如何获得Waker。关于doc看起来获得 Waker 的唯一方法是使用另一个接受 RawWakernew_unchecked。从那里我得到了here从那里here ,我只是蜷缩在地板上开始哭泣。

最佳答案

future 堆栈的这一部分不是打算由许多人实现的。我看到的粗略估计可能会有 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()) }
}

开始于 Future::poll ,我们看到我们需要一个 Pin future 和Context . Context 是从 Waker 创建的这需要 RawWaker . RawWaker 需要 RawWakerVTable .我们以最简单的方式制作所有这些作品:

  • 由于我们不尝试支持 NotReady 情况,因此我们实际上不需要为该情况做任何事情,而是可以 panic 。这也意味着 wake 的实现可以是空操作。

  • 因为我们不是为了提高效率,所以我们不需要为我们的 waker 存储任何数据,所以 clonedrop 基本上可以是无操作也是如此。

  • 确定 future 的最简单方法是Box,但这不是最有效的方法。


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

关于asynchronous - 如何在不使用任何外部依赖项的情况下执行异步/等待功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56252798/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com