每个“等待”运算符都会导致状态机吗?

请考虑以下代码:

public async Task GetString() { //Some code here... var data = await A(); //Some more code... return data; } private async Task A() { //Some code here.. var data = await B(); //manipulating data... return data; } private async Task B() { //Some code here.. var data = await C(); //manipulating data... return data; } private async Task C() { //Some code here.. var data = await FetchFromDB(); //manipulating data... return data; } private async Task FetchFromDB() { return await SOME_HTTP_REQUEST; } 

此代码演示了最基本的function – 嵌套异步方法。 每种方法都会转化为状态机吗? 或者编译器是否足够复杂以生成更高效的结构? 在我的一些项目中,UI / WebAPI和I / O调用之间有大约20种方法 – 这是否会影响异步 – 等待开销(例如状态机)和非阻塞线程优势之间的权衡? 我的意思是,例如,如果4个状态机的开销(4个嵌套的异步方法)等于50ms的阻塞I / O(就​​权衡而言),则20状态机将等于更长的I / O延迟( 250毫秒)?

每个方法都有一个状态机,是的。

请记住,状态机的“开销”主要是一个对象的分配(那个和几个goto ,这将是相当快的),所以你执行任何类型的“优化”来删除它是与不创建一次类的实例相同。

至于它的成本是否大于或小于同步工作,那么根据您的应用程序和硬件的具体情况,您将需要执行性能基准测试。

在这种情况下await并不重要。 每个async方法都会生成一个状态机 (即使它根本没有await s)。

你可以通过这个TryRoslyn示例看到它。

如果您遇到不需要状态机的情况,那么该方法实际上不需要像这样的async ,例如:

 private async Task D() { var data = await FetchFromDB(); return data; } 

您可以删除async关键字及其附带的状态机:

 private Task D() { return FetchFromDB(); } 

但除此之外,你实际上需要状态机,如果没有它, async方法就无法运行。

您应该注意,与使用async-await节省的资源相比,开销非常小,通常可以忽略不计。 如果您意识到情况并非如此(通过测试),您可能应该让该操作同步。

每种方法都会转化为状态机吗? 或者编译器是否足够复杂以生成更高效的结构?

不,编译器将为每个调用生成一个状态机。 编译器不检查方法的语义调用链。 它将仅基于方法生成状态机。

在查看编译代码时,您可以清楚地看到:

编译器生成的代码:

这会影响异步等待开销(例如状态机)和非阻塞线程优势之间的权衡吗?

您必须测试您的代码才能说出来。 通常,当您需要吞吐量时,异步IO很好。 如果您的异步方法将被多个呼叫者同时点击,您将能够看到其中的好处。 如果没有,您可能看不到性能提升的任何影响。 再次,对代码进行基准测试