Mat*_*nti 3 asynchronous future rust
我正在尝试创建最简单的示例,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.
}
Run Code Online (Sandbox Code Playgroud)
async/await
这仍然是一个夜间功能,在可预见的未来可能会发生变化。Future
实现,我知道tokio
.我模糊的理解是,首先,我需要完成Pin
任务。所以我继续前进
let pinned_task = Pin::new(&mut task);
Run Code Online (Sandbox Code Playgroud)
但
the trait `std::marker::Unpin` is not implemented for `std::future::GenFuture<[static generator@src/main.rs:7:18: 9:2 {}]>`
Run Code Online (Sandbox Code Playgroud)
所以我想,当然,我可能需要Box
它,所以我确定它不会在内存中移动。有点令人惊讶的是,我得到了同样的错误。
到目前为止我能得到的是
let pinned_task = unsafe {
Pin::new_unchecked(&mut task)
};
Run Code Online (Sandbox Code Playgroud)
这显然不是我应该做的。即便如此,假设我已经掌握了Pin
ned Future
。现在我需要以poll()
某种方式。为此,我需要一个Waker
.
所以我试图环顾四周,看看如何获得Waker
. 在文档上,看起来获取 a 的唯一方法Waker
是使用另一个new_unchecked
接受 a 的方法RawWaker
。从那里我到这里,从那里到这里,我只是蜷缩在地板上开始哭泣。
期货堆栈的这一部分并不打算由许多人实施。我所看到的粗略估计可能会有 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()) }
}
Run Code Online (Sandbox Code Playgroud)
从 开始Future::poll
,我们看到我们需要一个Pin
ned 未来和一个Context
. Context
是从 a 创建的,Waker
它需要一个RawWaker
. ARawWaker
需要一个RawWakerVTable
. 我们以最简单的方式创建所有这些部分:
由于我们不试图支持NotReady
案例,因此我们实际上不需要为该案例做任何事情,反而可能会感到恐慌。这也意味着 的实现wake
可以是无操作的。
因为我们并不想成为高效的,我们并不需要存储任何数据,我们之韵,所以clone
并drop
可以基本上是空操作为好。
固定未来的最简单方法就是Box
它,但这不是最有效的可能性。
如果你想支持NotReady
,最简单的扩展就是有一个繁忙的循环,永远轮询。一个稍微更有效的解决方案是有一个全局变量,表明有人已经调用wake
并阻止它成为真。