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()) }
}