代码之家  ›  专栏  ›  技术社区  ›  shay__

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

  •  9
  • shay__  · 技术社区  · 11 年前

    请考虑以下代码:

    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毫秒)?

    3 回复  |  直到 11 年前
        1
  •  13
  •   Community Mohan Dere    6 年前

    await 在这种情况下不重要。 每个 async 方法将生成状态机 (即使没有 等候 完全是)。

    你可以用 this TryRoslyn example .

    如果您有不需要状态机的情况,那么方法实际上不需要 异步的 比如这个:

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

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

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

    否则,您实际上需要状态机和 异步的 没有它,方法无法运行。

    您应该注意到,与使用 async-await 。如果你意识到情况并非如此(通过测试),你可能应该让操作同步。

        2
  •  8
  •   Servy    11 年前

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

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

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

        3
  •  5
  •   Yuval Itzchakov    11 年前

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

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

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

    Compiler generated code:

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

    你必须测试你的代码才能说出来。通常,异步IO在需要through put时很好。如果您的异步方法将被多个调用方同时命中,那么您将能够看到好处。如果没有,您可能看不到性能提高的任何效果。再次,对代码进行基准测试。

    推荐文章