我刚开始在.Net 4.5中开始使用异步/等待。我最初好奇的一件事是,为什么async关键字是必需的?我读到的解释是,它是一个标记,因此编译器知道一个方法在等待。但是似乎编译器应该能够在没有关键字的情况下解决问题。那还有什么作用呢?
我刚开始在.Net 4.5中开始使用异步/等待。我最初好奇的一件事是,为什么async关键字是必需的?我读到的解释是,它是一个标记,因此编译器知道一个方法在等待。但是似乎编译器应该能够在没有关键字的情况下解决问题。那还有什么作用呢?
Answers:
这里有几个答案,并且所有人都在谈论异步方法的作用,但是没有一个人回答这个问题,这就是为什么async
需要将关键字用作函数声明中的关键字。
这不是“指导编译器以特殊方式转换函数”;await
一个人就能做到。为什么?由于C#已经具有另一种机制,其中方法主体中存在特殊关键字会导致编译器在方法主体上执行极端(非常类似于async/await
)转换yield
。
除了yield
在C#中不是它自己的关键字,理解原因也将解释async
。与大多数支持这种机制的语言不同,在C#中,您不必说yield value;
必须说yield return value;
。为什么?因为它是在C#已经存在之后添加到语言中的,并且假设某个地方的某个人可能已经将其yield
用作变量名是非常合理的。但是,由于没有在<variable name> return
语法上正确的先前存在的场景,因此yield return
对该语言进行了添加,以使其能够引入生成器,同时保持与现有代码的100%向后兼容性。
这就是为什么将async
其添加为函数修饰符的原因:避免破坏用作await
变量名的现有代码。由于尚无任何async
方法,因此旧代码不会无效,在新代码中,编译器可以使用async
标记的存在来知道await
应将其视为关键字而不是标识符。
async
可以放弃指定关键字的要求?显然,这将是一次BC中断,但可以认为它影响很少的项目,并且是升级的直接要求(即更改变量名)。
它将方法从普通方法更改为带有回调的对象,这需要完全不同的代码生成方法
并且当发生如此剧烈的事情时,习惯将其清楚地表示出来(我们从C ++中学到了这一课)
async
s时它们会有所帮助,这样它们就不会一个接一个地运行,而是同时运行(如果至少有线程可用)
Task<T>
实际上都具有方法的特性async
-例如,您可能只运行了一些业务/工厂逻辑,然后委托给其他一些返回的方法Task<T>
。async
方法Task<T>
在签名中的返回类型为,但实际上并不返回Task<T>
,而是返回T
。为了在不使用async
关键字的情况下弄清所有这些情况,C#编译器将不得不对该方法进行各种深度检查,这可能会使其速度大大降低,并导致各种歧义。
使用诸如“异步”或“不安全”之类的关键字的整个想法是消除关于如何对待它们修改的代码的歧义。对于async关键字,它告诉编译器将修改后的方法视为不需要立即返回的东西。这允许使用该方法的线程继续执行而不必等待该方法的结果。这实际上是代码优化。
好,这是我的看法。
有几十年来被称为协程的东西。(“ Knuth and Hopper”类“数十年”)它们是子例程的概括,例如,它们不仅在函数的start和return语句中获取和释放控制,而且还在特定点(暂停点)进行控制。子例程是没有暂停点的协程。
使用C宏可以轻松实现它们,如以下有关“ protothreads”的论文所示。(http://dunkels.com/adam/dunkels06protothreads.pdf)阅读。我会等...
这样做的底线是宏会在每个挂起点创建一个big switch
以及一个case
标签。在每个挂起点,该函数都存储紧随其后的case
标签的值,以便它知道下次调用时在哪里恢复执行。然后它将控制权返回给调用者。
无需修改“原型线程”中描述的代码的明显控制流即可完成此操作。
现在想象一下,您有一个大循环依次调用所有这些“ protothreads”,并且在单个线程上同时执行“ protothreads”。
这种方法有两个缺点:
两种方法都有解决方法:
而且,如果您有编译器支持来执行宏和变通方法所做的重写工作,那么,您可以按照您的意图编写protothread代码,并使用关键字插入悬挂点。
而这也正是async
和await
都是关于:创建(无堆栈)协同程序。
C#中的协程被定义为(通用或非通用)类的对象Task
。
我发现这些关键字极具误导性。我的思想阅读是:
async
作为“可疑”await
作为“暂停直到完成”Task
作为“未来……”现在。我们真的需要标记功能async
吗?除了说应该触发代码重写机制以使函数成为协程外,它还解决了一些歧义。考虑下面的代码。
public Task<object> AmIACoroutine() {
var tcs = new TaskCompletionSource<object>();
return tcs.Task;
}
假设这async
不是强制性的,这是协程还是正常功能?编译器是否应该将其重写为协程?两种可能都有不同的最终语义。