我正在尝试创建最简单的示例,该示例可以让 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
的存在。 我无助、笨拙的努力
我模糊的理解是,首先,我需要关闭
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)
};
这显然不是我应该做的。即便如此,假设我已经掌握了
Pin
ned Future
。现在我需要以某种方式对其进行 poll()
。为此,我需要一个 Waker
。所以我试着四处看看如何获得
Waker
。在 doc 上,看起来获得 Waker
的唯一方法是使用另一个接受 new_unchecked
的 RawWaker
。从那里我得到了 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
ned future 和一个 Context
。 Context
是从需要 Waker
的 RawWaker
创建的。 RawWaker
需要 RawWakerVTable
。我们以最简单的方式创建所有这些部分:NotReady
案例,因此我们实际上不需要为该案例做任何事情,反而可能会感到 panic 。这也意味着 wake
的实现可以是 no-ops。 clone
和 drop
基本上也可以是 no-ops。 Box
,但这并不是最有效的可能性。 如果你想支持
NotReady
,最简单的扩展就是有一个繁忙的循环,永远轮询。一个稍微更有效的解决方案是使用一个全局变量来指示有人调用了 wake
并阻止它变为真。关于asynchronous - 如何在不使用任何外部依赖项的情况下执行 async/await 函数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56252798/