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

时间:2015-03-09 14:20:10

标签: c# asp.net async-await clr

请考虑以下代码:

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

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

3 个答案:

答案 0 :(得分:10)

在这种情况下,

await无关紧要。 每个async方法都会生成一个状态机(即使它根本没有await个。)

您可以使用this TryRoslyn example查看。

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

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

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

private Task<string> D()
{
    return FetchFromDB();
}

但是否则,你实际上需要状态机,如果没有它,async方法就无法运行。

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

答案 1 :(得分:5)

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

请记住&#34;开销&#34;状态机主要是一个对象的分配(那个和几个goto s,这将是非常快的),所以任何类型的&#34;优化&#34;你执行删除它与没有创建一次类的实例相同。

关于它的成本是否大于或小于同步工作,根据您的应用程序的具体情况,您需要执行性能基准测试。硬件肯定知道。

答案 2 :(得分:3)

  

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

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

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

Compiler generated code:

  

这是否会影响异步等待开销之间的权衡(例如   作为状态机)和非阻塞线程的好处?

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