异步等待的极简主义实现

时间:2014-01-28 08:08:33

标签: c# asynchronous async-await

尝试理解为什么.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 documentation表示如果目标不包含await语句,编译器将同步执行代码 - 但那么重点是什么? - 当然await async关键字只是用于异步使用。那为什么要make它如此复杂,而不是使用单一指令?)

3 个答案:

答案 0 :(得分:3)

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

但是,编译器坚持使用“async”修饰符标记方法的事实是一件好事 - 它允许您检查方法是否将同步/异步运行而不必深入研究其实施。它还告诉您是否必须/ {能够await它。我相信这些是强制使用两个关键字的原因,而不仅仅是一个。

类似的情况是:为什么你需要用“公共”访问修饰符来标记接口实现方法,即使它不能是私有/内部/受保护/受保护的内部?似乎多余的权利?但它确实提高了可读性。

答案 1 :(得分:2)

我对这个主题有一个blog post。主要原因是向后兼容(允许await关键字为上下文关键字)。在阅读代码时,将async关键字作为指标也很好。

另请参阅主题Eric Lippert's blog post以及他的comments on another postChannel9MSDN forumsright here on SO

答案 2 :(得分:1)

指定async关键字即时提示必须从头开始重写此方法的内部以支持async / await模型。您可能已经意识到,生成的IL看起来很像您的原始方法。您可能会认为这种重写也可能是隐含的,但在某种程度上明确允许这种情况发生是有意义的。

另一方面,你有一个有效的观点:当使用IEnumerable关键字隐式实现yield时会发生类似的事情,async关键字也与enumerated模型略有相似之处一台状态机。并且不存在在此类方法之前放置{{1}}关键字的要求。