异步等待的极简实现

问题描述 投票:0回答:3

尝试理解为什么 .NET 以他们的方式实现async-await

当更改简单的代码部分以使用 async-await 时,似乎最不需要的工作就是使用 async-await 指令标记调用方法和被调用方法:

private async void OnGuiClick(object sender, EventArgs args)
{
  textBox1.Text = await Work();
}

private async Task<string> Work()
{
  await Task.Delay(2000);
  return "Result";
}

为什么 .NET 坚持两者兼而有之? 即,最好使用单个关键字指定必须立即在工作线程上异步计算表达式 - 同时调用 GUI 线程被释放以执行其他任务,但将再次连接以执行剩余代码一次工作线程完成了。

是否有更简单或更好的方法来分配工作线程来处理 Work 方法,然后自动(无需诉诸 Invoke(...))确保相同的调用 GUI 线程处理结果? 为什么不做这样的事情:

private void OnGuiClick(object sender, EventArgs args)
{
  textBox1.Text = <'some async directive'> Work();
}

private string Work()
{
  Thread.Sleep(2000);
  return "Result";
}

MSDN文档指出,如果目标不包含await语句,编译器将同步执行代码 - 但那有什么意义呢? - 当然await async关键字仅用于异步使用。那为什么让它如此复杂,而不是使用单个指令?)

c# asynchronous async-await
3个回答
4
投票

你提出了一个很好的例子 - 我相信编译器只真正需要“await”关键字。我认为它不关心“异步”修饰符。

然而,事实上编译器坚持你用“async”修饰符标记你的方法是一件好事——它允许你检查一个方法是否会同步/异步运行,而不必深入研究它的实现。它还告诉您是否必须/能够

await
它。我相信这些是强制使用两个关键字(而不仅仅是一个关键字)的原因。

类似的情况是:为什么需要使用“public”访问修饰符来标记接口实现方法,即使它不能是私有/内部/受保护/受保护的内部?看起来多余吧?然而,它确实增加了可读性。


2
投票

我有一篇关于该主题的博客文章。主要原因是为了向后兼容(允许

await
关键字成为 contextual 关键字)。当您阅读代码时,使用
async
关键字作为指示符也很好。

另请参阅 Eric Lippert 关于该主题的博客文章,以及他的另一篇文章评论、Channel9MSDN 论坛就在 SO


1
投票

指定

async
关键字立即暗示该方法的内部结构必须从头开始重写以支持
async
/
await
模型。您可能知道,生成的 IL 看起来与您的原始方法不太一样。您可能会争辩说这种重写也可能是隐式的,但在某种程度上明确允许这种情况发生是有意义的。

另一方面,你有一个有效的观点:使用

IEnumerable
关键字隐式实现
yield
时会发生类似的情况,这也有点类似于
async
模型,因为它也创建了一个状态机。并且不存在在此类方法之前放置
enumerated
关键字的要求。

© www.soinside.com 2019 - 2024. All rights reserved.