尝试理解为什么 .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关键字仅用于异步使用。那为什么让它如此复杂,而不是使用单个指令?)
你提出了一个很好的例子 - 我相信编译器只真正需要“await”关键字。我认为它不关心“异步”修饰符。
然而,事实上编译器坚持你用“async”修饰符标记你的方法是一件好事——它允许你检查一个方法是否会同步/异步运行,而不必深入研究它的实现。它还告诉您是否必须/能够
await
它。我相信这些是强制使用两个关键字(而不仅仅是一个关键字)的原因。
类似的情况是:为什么需要使用“public”访问修饰符来标记接口实现方法,即使它不能是私有/内部/受保护/受保护的内部?看起来多余吧?然而,它确实增加了可读性。
指定
async
关键字立即暗示该方法的内部结构必须从头开始重写以支持 async
/await
模型。您可能知道,生成的 IL 看起来与您的原始方法不太一样。您可能会争辩说这种重写也可能是隐式的,但在某种程度上明确允许这种情况发生是有意义的。
另一方面,你有一个有效的观点:使用
IEnumerable
关键字隐式实现 yield
时会发生类似的情况,这也有点类似于 async
模型,因为它也创建了一个状态机。并且不存在在此类方法之前放置 enumerated
关键字的要求。