【问题标题】:Will every 'await' operator result in a state machine?每个“等待”运算符都会产生状态机吗?
【发布时间】:2015-05-10 17:50:15
【问题描述】:

请考虑以下代码:

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 个嵌套异步方法)的开销等于 50 毫秒的阻塞 I/O(就权衡而言),那么 20 个状态机是否等于更长的 I/O 延迟( 250 毫秒)?

【问题讨论】:

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


    【解决方案1】:

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

    您可以通过 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 节省的资源相比,通常可以忽略不计。如果您意识到情况并非如此(通过测试),您可能应该使该操作同步。

    【讨论】:

    • 他没有async没有await的方法;那不是问题。他基本上是在询问该方法是否会被内联,以便只需要创建一个状态机,而不是为每个方法创建一个。
    • @Servy 没有说 OP 做了。
    【解决方案2】:

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

    请记住,状态机的“开销”主要是分配一个对象(以及一些 gotos,这将是相当快的),因此您可以进行任何类型的“优化”执行删除它与不创建一个类的实例一次相同。

    至于它的成本是否高于或低于同步工作,这是您需要根据应用程序和硬件的具体情况进行性能基准测试才能确定的事情。

    【讨论】:

    • 谢谢,我会将其标记为答案,因为您是第一个回答我所有问题的人,尽管 @Yuval Itzchakov 和 i3arnon 也提供了出色的答案。非常感谢大家。
    【解决方案3】:

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

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

    查看编译后的代码可以清楚地看到:

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

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

    【讨论】:

      猜你喜欢
      • 2013-10-19
      • 2013-08-31
      • 1970-01-01
      • 2015-06-30
      • 2014-08-09
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 2020-05-13
      相关资源
      最近更新 更多